Introduction

In this article the issues concerning constant definitions (const)
and constant expressions (contexpr) are discussed. The examples, concerning constants,
run in GCC 4.7.0, Visual Studio 2008, Visual Studio 2010 and Visual Studio 11. The examples dealing with constexpr run in GCC 4.7.0, but not in Visual Studio (they are not
implemented in Visual C++ 11 yet).

Constants in the Global or Namespace Scope

Constants in the global or namespace scope (if not declared
extern) have internal linkage. This means that such constants can be defined in
an h-file and used in various modules without any errors concerning duplicate
definitions, etc. You may put the wordstatic, but this is superfluous.

This program runs both in Visual Studio and GCC 4.7.0. The issue is that constants, in contrast to variables, have internal linkage.

The problem is when we start using constants in places, where they have to be defined at compile time, for example as the size of an array in the array definition:

double a[N];

Here N should be defined at compile time. In order to guarantee that some special conditions can be met. Let’s look at some problems. If a double constant
is defined, it cannot be used in the array definition:

In C++11 it is possible to define constants, functions and classes so that they can be used to define other objects at compile time. A special keyword,
constexpr, is used to define such constructs. In general, expressions available at compile time are called constant expressions.
There are special conditions imposed on functions and classes so that they can be defined with the constexpr keyword. In the above-mentioned cases,
the code may be modified like that (valid in GCC 4.7.0):

Constants in Class Scope

Static constants defined in class scope have external linkage, which means there should be one module where they are fully defined. Integer static constants can have their values specified immediately in the declaration:

struct S
{
staticconstint n = 25;
double a[n];
};

This works fine for an array, but if a reference to a constant is used anywhere in the program, the constant should be defined on the namespace level, like this:

constint S::n;

Sometimes, a reference can be required in unexpected circumstances. Consider the following program:

In this program, all the "constants" behave naturally, and it's easy to define them - without any extra effort. The program will print:

515127
-82
5127
-82
c: 12345678abcdef03
z: 122 z

The only small problem is the value z. Look at the last line: we have to convert the value to char type explicitly in order to print is as a character. By default, it is printed as an integer because z is an enumerator.

With other types, the situation is different. If we use an ordinary const, the values cannot be specified in the declaration, but only in the definition in the global namespace scope. For example:

struct S
{
staticconstdouble p;
};
constdouble S::p = 7.5;

This works well for a single module, but it is not always good, when several modules are defined. Consider the following program, composed of several modules:

Contrary to most programmers’ expectations, the program will often output:

100010000

The last value will often (not always, it depends upon the system) will be 0, not 100. The reason is, that static constants, whose value are initialized in other modules, are not guaranteed to get values before the execution of main, which means that the B::d value may not be available when div2 is defined. This can lead to a lot of errors.

Now, in C++11,constexpr
can help solve these problems. First of all, constexpr can be used for both int
and double types and they can both be initialized inside the class. The values are guaranteed to be available at compile time. So, you are safe to use them. You may rewrite the above modules as follows:

Consexpr Functions

The general problem is that is you define constexpr objects (constexpr constants), as opposed to const
objects (ordinary constants), you may only initialize them with constant expressions, where ordinary functions are not allowed, but only calls to constexpr functions. A constexpr functionshould satisfy the following conditions:

its body must have only one statement, which should be a return with a non-void value (some asserts are allowed as well);

the value of the function and it’s parameters (if any) should be of types allowed as constexpr.

In order to write sophisticated algorithms, the only choice you have is to use recursion. There is a minimum limit on the depth of the recursion, which should be allowed by an implementation: 512.

Constexpr functions can be mutually recursive, but the function must be fully defined before it is used to define a constexpr object. A constexpr function may be called with non-constexpr arguments (for example, variables), but in this case its value will not be a constant expression. You may not define a constexpr function with the same name and parameters as another non-constexpr function.

The C++11 Standard does not require functions in <cmath> to be constexpr, which means that, as a general rule, functions, like sin(x) and sqrt(x), cannot be used in constant expressions. But, in GCC 4.7.0, they are defined as contsexpr functions, which is an extension to the Standard. If, in a particular implementation, sqrt is not defined as constexpr, you may define your own constexpr function, but you have to call it differently, say Sqrt. Such definition may look like this (we have defined the auxiliary functions Abs and Sqrt_impl):

Types that Can Be Used in Constant Expressions

The C++11 Standard defines so called literal types, which can be used in constant expressions. A literal typeis:• an arithmetic type (an integral, floating-point, character type or the bool type);• a pointer type;• a reference type to a literal type (for example, int& or double&);• an array of literal type;• a literal class.

A literal class has the following properties:• it does not have a user-defined destructor and all of its base classes do not have user-defined destructors;• its non-static data members and base classes are of literal types;• all its non-static data members are initialized, using constant expressions;• it satisfies one of the following two conditions:

it has no user-provided constructors, no initializers for non-static data members, no private or protected non-static data members, no base classes, and no virtual functions;

it has at least one constexpr constructor or constructor template, in addition to possible copy and move constructors; a constexpr constructor always has an empty body, but allows initialization of all the class members.

So, constructors can be defined as constexpr. Member functions can be constexpr, if they are not virtual. In constant expressions, you may use pointers, but you are not allowed to access data allocated on the heap using new.

How to Initialize Member Arrays in Consexpr Classes

The difficulty is that std::string and std::vector and other containers cannot be used in constant expressions. You have to use only literal types. Let’s define a literal array class: we’ll call it ConstArray, which is an array of fixed size, which can be used in constant expressions.The challenge is to initialize an array member in a class, which depends upon parameters. You are not allowed to use non-constexpr functions or constructors. Let’s first consider a simple example of an array of three elements:

The last operator is not a constant expression and cannot be used in constant expressions. It's important to know that constexpr member functions do not have to be qualified as const: the const qualifier is automatically assumed.

If we’d like to compare ConstString values it is also possible. Since we have to rely only on recursive functions if we want our values to remain
in the realm of constant expressions (Here again we need to define an auxiliary function):