Professional C__ - Marc Gregoire [142]
The constexpr Keyword
The constexpr keyword is new in C++11. C++ always had the notion of constant expressions and in some circumstances, constant expressions are required. For example when defining an array, the size of the array needs to be a constant expression. Because of this restriction, the following piece of code is not valid in C++.
const int getArraySize() { return 32; }
int main()
{
int myArray[getArraySize()]; // Invalid in C++
return 0;
}
Using the new constexpr keyword, the getArraySize() function can be redefined as follows:
constexpr int getArraySize() { return 32; }
int main()
{
int myArray[getArraySize()]; // OK with C++11
return 0;
}
Code snippet from Constexpr\constexpr.cpp
You can even do something like this:
int myArray[getArraySize() + 1]; // OK with C++11
The benefit of using constexpr is that the compiler can optimize your code much better during the compilation process. Declaring a function as constexpr imposes a few limitations on what that function can do.
If the constexpr function is a member of a class, the function cannot be virtual.
The return type of the function should be a literal type or a reference to a literal type. It cannot be void.
All the function arguments should be literal types or references to literal types.
The function body should be in the form {return expression;} where expression is a constant expression after argument substitution. expression is allowed to call other constexpr functions.
A constexpr function cannot be called until it’s defined in the translation unit because the compiler needs to know the complete definition.
These limitations are in place because the compiler must be able to evaluate a constexpr function at compile time.
By defining a constexpr constructor you can create constant expression variables of user-defined types. A constexpr constructor should satisfy the following requirements.
All the constructor arguments should be literal types or references to literal types.
The constructor body cannot be a function-try-block.
The constructor body should be empty.
All data members should be initialized with constant expressions.
For example, the following Rect class defines a constexpr constructor satisfying the previous requirements and also defines a constexpr getArea() method that is performing some calculation.
class Rect
{
public:
constexpr Rect(int width, int height)
: mWidth(width), mHeight(height) {}
constexpr int getArea() const { return mWidth * mHeight; }
private:
int mWidth, mHeight;
};
Code snippet from Constexpr\constexprClasses.cpp
Using this class to declare a constexpr object is straightforward:
constexpr Rect r(8, 2);
int myArray[r.getArea()]; // OK with C++11
Code snippet from Constexpr\constexprClasses.cpp
The static Keyword
There are several uses of the keyword static in C++, all seemingly unrelated. Part of the motivation for “overloading” the keyword was attempting to avoid having to introduce new keywords into the language.
static Data Members and Methods
You can declare static data members and methods of classes. static data members, unlike non-static data members, are not part of each object. Instead, there is only one copy of the data member, which exists outside any objects of that class.
static methods are similarly at the class level instead of the object level. A static method does not execute in the context of a specific object.
Chapter 7 provides examples of both static members and methods.
static Linkage
Before covering the use of the static keyword for linkage, you need to understand the concept of linkage in C++. C++ source files are each compiled independently, and the resulting object files are linked together. Each name in a C++ source file, including functions and global variables, has a linkage that is either internal or external. External linkage means that the name is available from other source files. Internal linkage (also called static linkage) means that it is not. By default, functions and global variables have