HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

C++-safe way to use using inside headers

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
wayheadersusingsafeuseinside

Problem

I have this C++ 14 code in a project of mine.

Enhedron/Util/Enum.h:

#ifndef ENHEDRON_UTIL_ENUM_H_
#define ENHEDRON_UTIL_ENUM_H_

#include 
#include 

namespace Enhedron { namespace Util { namespace Impl { namespace Enum {
    using std::runtime_error;
    using std::underlying_type_t;

    /**
     * Convert a value to an enum safely. The enum must have "LAST_ENUM_VALUE" as the last
     * enumerated value, and must be a simple enum starting at 0 and being densely populated. For example:
     *
     *      enum class MyEnum {
     *          VALUE_0,
     *          VALUE_1,
     *          LAST_ENUM_VALUE = VALUE_1
     *      };
     */
    template
    Enum toEnum(Value value) {
        if (value >= 0 && value >(Enum::LAST_ENUM_VALUE)) {
            return static_cast(value);
        }

        throw runtime_error("Value out of range for enum");
    }

    /**
     * Tag a type with an enumerated value to create a distinct type. Useful to differentiate values of the same type.
     * For example, to stop first and last names being interchangeable in the type system:
     *      enum class Name {
     *          FIRST,
     *          LAST
     *      };
     *
     *      using FirstName = TaggedValue;
     *      using LastName = TaggedValue;
     */
    template
    class TaggedValue final {
        Value value;
    public:
        TaggedValue(Value value) : value(move(value)) { }

        Value& operator*() { return value; }
        const Value& operator*() const { return value; }

        Value* operator->() { return &value; }
        const Value* operator->() const { return &value; }
    };
}}}}

namespace Enhedron { namespace Util {
    using Impl::Enum::toEnum;
    using Impl::Enum::TaggedValue;
}}

#endif /* ENHEDRON_UTIL_ENUM_H_ */


Some specific things I'm unsure of:

-
Is there a better way to define TaggedValue so that you don't have to mention the enum type and the enum value you want to use? i.e. getting the template argument Enum inf

Solution


  1. Auto Non-type template parameter



No, not possible, sorry, see this on SO.
I wish it could be done... but no, not in current standard.

  1. Complex namespaces and using



It is not causing problems to users of the header, but the question is: who will maintain the code? You? Only you?

If the answer is yes, then it sounds too complex for me. It would be much easier to have one header (e.g. common.hpp) with the usings within one private namespace (e.g. firda::detail in my case) where any implementation will go inside this namespace (e.g firda::detail::something) automatically sharing all the usings specified in one file like a convention (common usage, something anybody needs to read before altering your code).

To be honest, I use such header importing selected features to my global namespace (firda). It is not adviced to use using namespace std and the same apply to my namespace (do not use using namespace firda, I am the only one allowed to do so in my own projects).

You can run into problems after adding usings to that common header, but it is your code and you should be able to manage it.

If the answer is no, than you need some common convention and from my perspective, it is much easier to simply forget about usings (except inside functions/methods). You can use shortcuts (namespace alias) if you really need to (e.g. namespace ns1 = some::complex::namespace::chain) placed usually on top of the header (to be easily found). Writing std::something or ns1::something is not so much typing and explicity is much better for multiple-coworker scenairo.

If you have the convention to place all such usings on top of the header, than it can be found by anybody sharing this convention. So, the idea is not that bad after all, but I would still prefer namespace aliases and std:: prefixes.

Context

StackExchange Code Review Q#110098, answer score: 4

Revisions (0)

No revisions yet.