Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 987
Thomas Avatar asked Oct 13 '16 10:10

Thomas


People also ask

Which is better const or enum?

I would advice you to use enums only if you really need enumerated constants, or some additional functionality common for all items. That's of course depending on the type of application you are writing and what versions and devices you want to support.

What is the difference between enum and #define constant in C?

One of the differences between the two is that #define is a pre-processor directive while enum is part of the actual C language. #define statements are processed by the compiler before the first line of C code is even looked at!


2 Answers

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] (emphasis mine):

An enumeration is a distinct type with named constants.

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


As a side note, something similar applies if you use static constexpr data members in C++11/14:

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

This doesn't work as well and that's how I discovered the subtle differences between them.

I found help here on SO getting some nice hints out of the answer I've been given.
References to the standard are a plus to better explain what's going on under the hood.

Note that a static constexpr data member declaration like the one above is also a definition since C++17. Therefore you won't have to define it anymore and you'll be able to odr-use it directly instead.


As mentioned in the comments (thanks to @Yakk that confirmed this) I'm also trying to explain how it happens that the above mentioned named constants bind to a const reference.

[expr.const/3] introduces the integral constant expression and mentions unscoped enums by saying that it's implicitly converted to a prvalue.
[dcl.init.ref/5] and [class.temporary/2] do the rest, for they rule on reference binding and temporaries.

like image 183
skypjack Avatar answered Oct 19 '22 16:10

skypjack


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

Yes, that's the reason.

static const bool value = true;

would occupy memory, while

enum { value = true };

doesn't.

like image 6
πάντα ῥεῖ Avatar answered Oct 19 '22 14:10

πάντα ῥεῖ