constexpr - Variables and Objects

If you declare a variable as constexpr the compiler will evaluate them at compile time. This holds not only true for built-in types but also for instantiations of user-defined types. There are a few serious restrictions for objects in order to evaluate them at compile time.

To make the life for you and me easier I will use for built-in types like bool, char, int, and double the name variable. I will call the remaining data types as user-defined data types. These are for example std::string, types from the C++ library and user-defined data types. User-defined types holds typically built-in types.

Variables

By using the keyword constexpr the variable becomes a constant expression.

constexpr double myDouble= 5.2;

Therefore, I can use the variable in contexts that requires a constant expression. For example, if I want to define the size of an array. This has to be done at compile time.

For the declaration of constexpr variable you have to keep a few rules in mind.

The variable

is implicitly const.

has to be initialized.

requires a constant expression for initialization.

The rule makes sense. If I evaluate a variable at compile time, the variable can only depend on values that can be evaluated at compile time.

The objects are created by the invocation of the constructor. The constructor has a few special rules.

has to be declared as default or delete or the function body must be empty (C++11).

The constexpr user-defined type

can not have virtual base classes.

requires that each base object and each non-static member has to be initialized in the initialization list of the constructor or directly in the class body. Consequently, it holds that each used constructor (e.g of a base class) has to be constexpr constructor and that the applied initializers have to be constant expressions.

Sorry, but the details are even harder: cppreference.com. To make the theory obvious I define the class MyInt. MyInt shows the just mentioned points. The class has in addition constexpr methods. There are special rules for constexpr methods and functions. This rules will follow in the next post, so we can concentrate in this post on the essentials about variables and user-defined types.

The class MyInt has three constructors. A constexpr default constructor (line 8) and a constructor taking two (line 9) and taking one argument (line 10). The constructor with two arguments is a constexpr constructor. Therefore, its body is empty. This holds not true for the non-constexpr constructor with one argument. The definition goes on with a defaulted copy-constructor (line 15) and a deleted move-constructor (line 16). Additionally, the class has two methods, but only the method getSum is a const expression. I can only define the variables myVal1 and myVal2 (line 26 and 27) in two ways if I want to use them in constexpr objects. At first, I can initialize them in the initialization list of the constructor (line 9); at second, I can initialize them in the class body (line 26 and 27). The initialization in the initialization list of the constructor has higher priority. It's not allowed to define both variables in the body of the constructor (line 11 and 12).

To put the theory to practice, here is the output of the program.

The program shows a few special points:

You can use a constexpr constructor at run time. Of course, the instance is no constant expression (line 36 and line 46).

If you declare a non-constant expression as constexpr, you will get a compiler error (line 52 and 57).

constexpr constructors can coexit with non-constexpr constructors. The same holds true for the methods of a class.

The key observation is: A constexpr object can only use constexpr methods.

But stop. What's the story about the two last lines 62 and 63 in the main function?

The proof

Quite straight forward. They are the twofold proof that the call myIntConst3.getSum() is performed at compile time.

At first, C++ requires that the size of an array has to be a constant expression. At second, static_assert evaluate its expression at compile time. If not, static_assert will not compile.

What's next?

I think, you know it already. In the next post I will write about contexpr functions. They have with C++11 a lot of restrictions that will almost disappear with C++14. constexpr functions in C++14 feels almost like normal functions. Of course, my points about functions will also hold for methods of classes.

Go to Leanpub/cpplibrary"What every professional C++ programmer should know about the C++ standard library".Get your e-book. Support my blog.