Search code examples
c++c++11enumsusing

How to do `using` of weak enums in C++11?


I have enum definition inside a class in the header:

namespace A {

class B {
 public:
  enum Value {
    VALUE1 = 1,
    VALUE2 = 2,
  };
};

}

And I want to use its values in a source file without prefix, like this:

#include "header"

int main() {
  someFn(VALUE1);

  return 0;
}

I have tried to using A::B::Value; but clang gives an error:

using declaration can not refer to class member


Even if I move enum outside of a class:

namespace A {

enum Value {
  VALUE1 = 1,
  VALUE2 = 2,
};    

}

and do using A::Value;, the error is gone, but the compiler complains about VALUE1:

use of undeclared identifier 'VALUE1'

Is there way to use values of enum without any prefixes, if the enum is defined somewhere else? - Using #defines is out of question.

If there is no way, then what is a possible issue about implementing such behavior in C++ Standard?


Solution

  • There are two reasons why your approaches fail:

    1. The first reason has been described by BЈовић: You cannot introduce the name of a nested type in a namespace scope, see [namespace.udecl]/8.

    2. When you write using A::B::Value;, only the name of the enum itself will be introduced in the current scope, not the name of all enumerators. This allows things like:

      namespace Values { enum Value{ VALUE1, VALUE2 }; }
      using Values::Value;  // don't pollute my scope with the enumerators
      
      Value v = Values::VALUE1;
      

    The second issue can be solved by introducing the enumerators individually:

    namespace A
    {
        namespace B
        {
            enum Value
            {
                  VALUE1
                , VALUE2
            };
        }
    }
    
    int main()
    {
        using A::B::Value;
        using A::B::VALUE1;
        using A::B::VALUE2;
    
        Value v = VALUE1;
        v = VALUE2;
    }
    

    Alternatively, as hvd suggested in a comment, you can use a using-directive to introduce all names of a namespace:

    namespace A
    {
        namespace B
        {
            enum Value
            {
                  VALUE1
                , VALUE2
            };
        }
    }
    
    int main()
    {
        using namespace A::B;
    
        Value v = VALUE1;
        v = VALUE2;
    }