Home > Enterprise >  Enum inside a templated class
Enum inside a templated class

Time:03-08

Let's say I have a class Class, which has an associated enum member Enum. The enum only makes sense in the context of this class, and therefore it is specified inside it. Then you can just call Class::Enum::Something from outside of the class, which is fine.

class Class
{
   public:
      enum class Enum : uchar
      {
          Something
      }
}

However, if the class Class is templated, you cannot do Class::Enum::Something, but you have to Class<T>::Enum::Something (or Class<>::Enum::Something if T has some default type).

template <typename T = double>
class Class
{
   public:
      enum class Enum : uchar
      {
          Something
      }
}

The Enum has to be the same for all Ts, since it's just a simple enum, but the T always has to be specified anyway.

My question is - is there a clever way of avoiding this?

CodePudding user response:

It is essential to understand that the wrapped enum type is a different type for different specializations of Class.

#include <type_traits>

template <typename T = double>
struct S
{
      enum class E : int { a };
};

static_assert(!std::is_same_v<S<>::E, S<int>::E>);  // !!!

It seems like you want this to actually be the same type, in which case you could break it out into a separate class and use private implementation inheritance to expose it via the class template specializations:

#include <type_traits>

namespace detail {
struct Base {
    enum class E : int { a };
};
}  // namespace detail;

template <typename T = double>
struct S : private detail::Base
{
    using Base::E;    
};

static_assert(std::is_same_v<S<>::E, S<int>::E>); // OK

However if you are set on supplying this enum as a member (alias declaration above) of the various class template specializations, you will need to qualify which specialization you refer to.

S<>::E;
S<int>::E;

The root problem you seem to want to solve is scoping, in which case you may use a namespace instead of class to wrap the associated enum:

namespace my_lib {

template <typename T = double>
struct S {};

enum class E : int { a };

}  // namespace my_lib

CodePudding user response:

Often it is more convenient to move everything that does not depend on the tempalte argument to a non-template base class:

#include <iostream>

class Base {
   public:
      enum class Enum
      {
          Something
      };

};

template <typename T = double>
class Class : public Base
{
};

int main() {
    std::cout << (Class<>::Enum::Something == Class<int>::Enum::Something);
}
  • Related