In § 6.5.2 (p. 239) we noted that the parameters and return type of a constexpr
function must be literal types. In addition to the arithmetic types, references, and pointers, certain classes are also literal types. Unlike other classes, classes that are literal types may have function members that are constexpr
. Such members must meet all the requirements of a constexpr
function. These member functions are implicitly const
(§ 7.1.2, p. 258).
An aggregate class (§ 7.5.5, p. 298) whose data members are all of literal type is a literal class. A nonaggregate class, that meets the following restrictions, is also a literal class:
• The data members all must have literal type.
• The class must have at least one constexpr
constructor.
• If a data member has an in-class initializer, the initializer for a member of built-in type must be a constant expression (§ 2.4.4, p. 65), or if the member has class type, the initializer must use the member’s own constexpr
constructor.
• The class must use default definition for its destructor, which is the member that destroys objects of the class type (§ 7.1.5, p. 267).
constexpr
ConstructorsAlthough constructors can’t be const
(§ 7.1.4, p. 262), constructors in a literal class can be constexpr
(§ 6.5.2, p. 239) functions. Indeed, a literal class must provide at least one constexpr
constructor.
A constexpr
constructor can be declared as = default
(§ 7.1.4, p. 264) (or as a deleted function, which we cover in § 13.1.6 (p. 507)). Otherwise, a constexpr
constructor must meet the requirements of a constructor—meaning it can have no return
statement—and of a constexpr
function—meaning the only executable statement it can have is a return
statement (§ 6.5.2, p. 239). As a result, the body of a constexpr
constructor is typically empty. We define a constexpr
constructor by preceding its declaration with the keyword constexpr
:
class Debug {
public:
constexpr Debug(bool b = true): hw(b), io(b), other(b) { }
constexpr Debug(bool h, bool i, bool o):
hw(h), io(i), other(o) { }
constexpr bool any() { return hw || io || other; }
void set_io(bool b) { io = b; }
void set_hw(bool b) { hw = b; }
void set_other(bool b) { hw = b; }
private:
bool hw; // hardware errors other than IO errors
bool io; // IO errors
bool other; // other errors
};
A constexpr
constructor must initialize every data member. The initializers must either use a constexpr
constructor or be a constant expression.
A constexpr
constructor is used to generate objects that are constexpr
and for parameters or return types in constexpr
functions:
constexpr Debug io_sub(false, true, false); // debugging IO
if (io_sub.any()) // equivalent to if(true)
cerr << "print appropriate error messages" << endl;
constexpr Debug prod(false); // no debugging during production
if (prod.any()) // equivalent to if(false)
cerr << "print an error message" << endl;