Home > Articles > Programming > C/C++

  • Print
  • + Share This
This chapter is from the book

This chapter is from the book

17.2 Enumeration Values versus Static Constants

In old C++ compilers, enumeration values were the only available possibility to have “true constants” (so-called constant-expressions) inside class declarations. However, this has changed during the standardization of C++, which introduced the concept of in-class static constant initializers. A brief example illustrates the construct:

struct TrueConstants {
     enum { Three = 3 };
     static int const Four = 4;
};

In this example, Four is a “true constant”—just as is Three.

With this, our Pow3 metaprogram may also look as follows:

// meta/pow3b.hpp

#ifndef POW3_HPP
#define POW3_HPP


//primary template to compute 3 to the Nth


template<int N>
class Pow3 {
  public:
    static int const result = 3 * Pow3<N-1>::result;
};

// full specialization to end the recursion
template<>
class Pow3<0> {
  public:
    static int const result = 1;
};

#endif //POW3_HPP

The only difference is the use of static constant members instead of enumeration values. However, there is a drawback with this version: Static constant members are lvalues. So, if you have a declaration such as

void foo(int const&);

and you pass it the result of a metaprogram

foo(Pow3<7>::result);

a compiler must pass the address of Pow3<7>::result, which forces the compiler to instantiate and allocate the definition for the static member. As a result, the computation is no longer limited to a pure “compile-time” effect.

Enumeration values aren’t lvalues (that is, they don’t have an address). So, when you pass them “by reference,” no static memory is used. It’s almost exactly as if you passed the computed value as a literal. These considerations motivate us to use enumeration values in all metaprograms throughout this book.

  • + Share This
  • 🔖 Save To Your Account