7.5.6. Literal Classes

Image

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 const7.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 Constructors

Although constructors can’t be const7.1.4, p. 262), constructors in a literal class can be constexpr6.5.2, p. 239) functions. Indeed, a literal class must provide at least one constexpr constructor.

Image

A constexpr constructor can be declared as = default7.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;


Exercises Section 7.5.6

Exercise 7.53: Define your own version of Debug.

Exercise 7.54: Should the members of Debug that begin with set_ be declared as constexpr? If not, why not?

Exercise 7.55: Is the Data class from § 7.5.5 (p. 298) a literal class? If not, why not? If so, explain why it is literal.


..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
13.58.50.156