Skip to main content
edited tags
Link
200_success
  • 144.2k
  • 22
  • 188
  • 473
deleted 1 character in body; edited tags; edited title
Source Link
Jamal
  • 34.9k
  • 13
  • 133
  • 237

C++ safe-safe way to use using inside headers

File: Enhedron/Util/Enum.h:Enhedron/Util/Enum.h:

  • Is there a better way to define TaggedValueTaggedValue 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 inferred from the type of tag.

  • I'm using a namespace scheme where every header file has a namespace Enhedron::Module::Impl::FileName which is by convention private to that file. Then at the end of the file, it will export those names into the module namespace Enhedron::Module. My concern is that use of using inside the "private" namespace. Any thoughsthoughts on whether this would cause problems?

C++ safe way to use using inside headers

File: Enhedron/Util/Enum.h:

  • 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 inferred from the type of tag.

  • I'm using a namespace scheme where every header file has a namespace Enhedron::Module::Impl::FileName which is by convention private to that file. Then at the end of the file, it will export those names into the module namespace Enhedron::Module. My concern is that use of using inside the "private" namespace. Any thoughs on whether this would cause problems?

C++-safe way to use using inside headers

Enhedron/Util/Enum.h:

  • 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 inferred from the type of tag.

  • I'm using a namespace scheme where every header file has a namespace Enhedron::Module::Impl::FileName which is by convention private to that file. Then at the end of the file, it will export those names into the module namespace Enhedron::Module. My concern is that use of using inside the "private" namespace. Any thoughts on whether this would cause problems?

Post Reopened by Mat, Mast, Simon Forsberg
Re worded the question to fit the guidelines and added real code.
Source Link

I'm wondering if there's any safe to use using in C++ header files. I'm looking at adopting a scheme something likeI have this (using the nested namespace proposalC++ 14 code in the example)a project of mine.

File: Enhedron/Util/Enum.h:

#ifndef ENHEDRON_UTIL_ENUM_H_
#define ENHEDRON_UTIL_ENUM_H_

#include <stdexcept>
#include <type_traits>

namespace MyProject::MyModule::Detail::MyFilenameEnhedron { namespace Util { namespace Impl { namespace Enum {
    using std::cout;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 PrivateMyEnum {
     *          VALUE_0,
     *          VALUE_1,
     *          LAST_ENUM_VALUE = VALUE_1
     *      };
    class ModulePrivate*/
    template<typename Enum, typename Value>
    Enum toEnum(Value value) {};
    class Public   if (value >= 0 && value <= static_cast<underlying_type_t<Enum>>(Enum::LAST_ENUM_VALUE)) {
            return static_cast<Enum>(value);
        }

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

namespace MyProject:   /**
     * 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:MyModule
     *      enum class Name {
     *          FIRST,
     *          LAST
     *      };
     *
     *      using FirstName = TaggedValue<Name, Name::DetailFIRST, {string>;
     *      using DetailLastName = TaggedValue<Name, Name::MyFilenameLAST, string>;
     */
    template<typename Enum, Enum tag, typename Value>
    class TaggedValue final {
        Value value;
    public:
        TaggedValue(Value value) :ModulePrivate; value(move(value)) { }

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

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

namespace MyProject::MyModuleEnhedron { namespace Util {
    using DetailImpl::MyFilenameEnum::Public;toEnum;
    using Impl::Enum::TaggedValue;
}} 

#endif /* ENHEDRON_UTIL_ENUM_H_ */

You'd have a project and module namespace. Each module would have a Detail namespace. Each file would have a namespace matching it's filename. By convention, you'd only use the modules detail namespace within that module, and the filename namespace within that header or source file. A the end of the header, you export any names either to the module or module detail namespace.

Normally I wouldn't use using in a header as it pollutes namespaces and can change the meaning of other headers. But with this scheme, is this still a problem in practice and what assumptions are required for it to work?

Some initial assumptionsspecific things I'm unsure of:

  • The project namespace doesn't clash with external code.
  • Everything within the project namespace sticks to the rules!

    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 inferred from the type of tag.

  • Possibly the Detail namespace is not used at the global level by external code. I don't think this is required though as Detail will take precedence inside the module namespace.

    I'm using a namespace scheme where every header file has a namespace Enhedron::Module::Impl::FileName which is by convention private to that file. Then at the end of the file, it will export those names into the module namespace Enhedron::Module. My concern is that use of using inside the "private" namespace. Any thoughs on whether this would cause problems?

I'm wondering if there's any safe to use using in C++ header files. I'm looking at adopting a scheme something like this (using the nested namespace proposal in the example).

namespace MyProject::MyModule::Detail::MyFilename {
    using std::cout;

    class Private {};
    class ModulePrivate {};
    class Public {};
}

namespace MyProject::MyModule::Detail {
    using Detail::MyFilename::ModulePrivate;
}

namespace MyProject::MyModule {
    using Detail::MyFilename::Public;
}

You'd have a project and module namespace. Each module would have a Detail namespace. Each file would have a namespace matching it's filename. By convention, you'd only use the modules detail namespace within that module, and the filename namespace within that header or source file. A the end of the header, you export any names either to the module or module detail namespace.

Normally I wouldn't use using in a header as it pollutes namespaces and can change the meaning of other headers. But with this scheme, is this still a problem in practice and what assumptions are required for it to work?

Some initial assumptions:

  • The project namespace doesn't clash with external code.
  • Everything within the project namespace sticks to the rules!
  • Possibly the Detail namespace is not used at the global level by external code. I don't think this is required though as Detail will take precedence inside the module namespace.

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

File: Enhedron/Util/Enum.h:

#ifndef ENHEDRON_UTIL_ENUM_H_
#define ENHEDRON_UTIL_ENUM_H_

#include <stdexcept>
#include <type_traits>

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<typename Enum, typename Value>
    Enum toEnum(Value value) {
        if (value >= 0 && value <= static_cast<underlying_type_t<Enum>>(Enum::LAST_ENUM_VALUE)) {
            return static_cast<Enum>(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<Name, Name::FIRST, string>;
     *      using LastName = TaggedValue<Name, Name::LAST, string>;
     */
    template<typename Enum, Enum tag, typename Value>
    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 inferred from the type of tag.

  • I'm using a namespace scheme where every header file has a namespace Enhedron::Module::Impl::FileName which is by convention private to that file. Then at the end of the file, it will export those names into the module namespace Enhedron::Module. My concern is that use of using inside the "private" namespace. Any thoughs on whether this would cause problems?

Post Closed as "Not suitable for this site" by Morwenn, 5gon12eder, Mast, Bjørn-Roger Kringsjå, Simon Forsberg
Source Link
Loading