Template Metaprogramming - Difference Between Using Enum Hack and Static Const
Asked Answered
D

4

61

I'm wondering what the difference is between using a static const and an enum hack when using template metaprogramming techniques.

EX: (Fibonacci via TMP)

template< int n > struct TMPFib {
  static const int val =
    TMPFib< n-1 >::val + TMPFib< n-2 >::val;
};

template<> struct TMPFib< 1 > {
  static const int val = 1;
};

template<> struct TMPFib< 0 > {
  static const int val = 0;
};

vs.

template< int n > struct TMPFib {
  enum {
    val = TMPFib< n-1 >::val + TMPFib< n-2 >::val
  };
};

template<> struct TMPFib< 1 > {
  enum { val = 1 };
};

template<> struct TMPFib< 0 > {
  enum { val = 0 };
};

Why use one over the other? I've read that the enum hack was used before static const was supported inside classes, but why use it now?

Detrital answered 31/1, 2010 at 17:47 Comment(2)
+1: a great question indeed, and I'd also like to see what the answers will be except for the obvious.Shoreward
static const allows types other than int. double for instance.Greataunt
U
40

Enums aren't lvals, static member values are and if passed by reference the template will be instanciated:

void f(const int&);
f(TMPFib<1>::value);

If you want to do pure compile time calculations etc. this is an undesired side-effect.

The main historic difference is that enums also work for compilers where in-class-initialization of member values is not supported, this should be fixed in most compilers now.
There may also be differences in compilation speed between enum and static consts.

There are some details in the boost coding guidelines and an older thread in the boost archives regarding the subject.

Unsettled answered 31/1, 2010 at 18:22 Comment(1)
I do not know if it is still true, by looking at the output of the compiler (godbolt), both snippets yields the same assembly code.Borden
S
12

For some the former one may seem less of a hack, and more natural. Also it has memory allocated for itself if you use the class, so you can for example take the address of val.

The latter is better supported by some older compilers.

Shoreward answered 31/1, 2010 at 17:54 Comment(5)
Thanks. Exactly the kind of answer I was looking for.Detrital
Personally I completely disagree. Then enum version seems more natural. Why is there a need for a physical variable? Enum is the representation of a const value. Using a static const int seems more like taking a step backwards to the time when we had to use macros to represent constant values.Holbrook
@Martin, what has the keyword enumeration to do with calculation? But point taken -- everyone can have their own point on that.Shoreward
@Martin - to be honest, I prefer using enums for this myself.Shoreward
I'm an enum guy too. An enum is essentially just a named integral constant, which seems to fit our needs in these cases just fine. It's an rvalue with no storage allocate for it. A static const int has storage allocated for it and and everything, which isn't really necessary.Abut
M
2

On the flip side to @Georg's answer, when a structure that contains a static const variable is defined in a specialized template, it needs to be declared in source so the linker can find it and actually give it an address to be referenced by. This may unnecessarily(depending on desired effects) cause inelegant code, especially if you're trying to create a header only library. You could solve it by converting the values to functions that return the value, which could open up the templates to run-time info as well.

Mallet answered 22/9, 2013 at 4:39 Comment(0)
S
0

"enum hack" is a more constrained and close-enough to #define and that helps to initialise the enum once and it's not legal to take the address of an enum anywhere in the program and it's typically not legal to take the address of a #define, either. If you don't want to let people get a pointer or reference to one of your integral constants, an enum is a good way to enforce that constraint. To see how to implies to TMP is that during recursion, each instance will have its own copy of the enum { val = 1 } during recursion and each of those val will have proper place in it's loop. As @Kornel Kisielewicz mentioned "enum hack" also supported by older compilers those forbid the in-class specification of initial values to those static const.

Sub answered 4/6, 2020 at 8:46 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.