Thomas Thomas - 1 month ago 6
C++ Question

In a type trait, why do people use enum rather than static const for the value?

For example, this is how I would write it, and it compiles and works just fine:

template<typename T> struct is_pointer<T*> {
static const bool value = true;
}


Then why do some people write the less obvious

template<typename T> struct is_pointer<T*> {
enum { value = true };
}


instead? Is it only because the
static const
variable uses a byte of memory, whereas the
enum
doesn't?

Answer

A notable difference is in the fact that the following code compiles and links:

template<typename>
struct is_pointer { };

template<typename T>  
struct is_pointer<T*> {
  enum { value = true };
};     

void f(const bool &b) { }

int main() {
  f(is_pointer<void*>::value);
}

The following does not work instead (you get an undefined reference to value):

template<typename>
struct is_pointer { };

template<typename T>
struct is_pointer<T*> {
  static const bool value = true;
};

void f(const bool &b) { }

int main() {
  f(is_pointer<void*>::value);
}

Of course, it doesn't work unless you add somewhere the following lines:

template<typename T>
const bool is_pointer<T*>::value;

That is because of [class.static.data]/3 (emphasis mine):

If a non-volatile non-inline const static data member is of integral or enumeration type, its declaration in the class definition can specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression ([expr.const]). The member shall still be defined in a namespace scope if it is odr-used ([basic.def.odr]) in the program and the namespace scope definition shall not contain an initializer. [...]

In other terms, static const bool value = true; is a declaration, not a definition and you cannot odr-use value.
On the other side, according with [dcl.enum/1]:

An enumeration is a distinct type with named constants.

Those named constants can be const referenced as shown in the example above.