Constexpr constructors (C++11)
Note: IBM supports selected
features of C++11, known as C++0x before its ratification. IBM will
continue to develop and implement the features of this standard. The
implementation of the language level is based on IBM's interpretation
of the standard. Until IBM's implementation of all the C++11 features
is complete, including the support of a new C++11 standard library,
the implementation may change from release to release. IBM makes no
attempt to maintain compatibility, in source, binary, or listings
and other compiler interfaces, with earlier releases of IBM's implementation
of the new C++11 features.
A constructor that is declared with a constexpr specifier is a constexpr constructor. Previously, only expressions of built-in types could be valid constant expressions. With constexpr constructors, objects of user-defined types can be included in valid constant expressions.
Definitions
of constexpr constructors must satisfy the following
requirements:
- The containing class must not have any virtual base classes.
- Each of the parameter types is a literal type.
- Its function body is = delete or = default;
otherwise, it must satisfy the following constraints:
- It is not a function try block.
- The compound statement in it must contain only the following statements:
- null statements
- static_assert declarations
- typedef declarations that do not define classes or enumerations
- using directives
- using declarations
- Each nonstatic data member and base class subobject is initialized.
- Each constructor that is used for initializing nonstatic data members and base class subobjects is a constexpr constructor.
- Initializers for all nonstatic data members that are not named by a member initializer identifier are constant expressions.
- When initializing data members, all implicit conversions that
are involved in the following context must be valid in a constant
expression:
- Calling any constructors
- Converting any expressions to data member types
The implicitly defined default constructor performs the set of initializations of the class that would be performed by a user-written default constructor for that class with no initializer and an empty compound-statement. If that user-defined default constructor would satisfy the requirements of a constexpr constructor, the implicitly defined default constructor is a constexpr constructor.
A constexpr constructor is implicitly inline.
The following examples demonstrate the
usage of constexpr constructors:
struct BASE {
};
struct B2 {
int i;
};
//NL is a non-literal type.
struct NL {
virtual ~NL() {
}
};
int i = 11;
struct D1 : public BASE {
//OK, the implicit default constructor of BASE is a constexpr constructor.
constexpr D1() : BASE(), mem(55) { }
//OK, the implicit copy constructor of BASE is a constexpr constructor.
constexpr D1(const D1& d) : BASE(d), mem(55) { }
//OK, all reference types are literal types.
constexpr D1(NL &n) : BASE(), mem(55) { }
//The conversion operator is not constexpr.
operator int() const { return 55; }
private:
int mem;
};
struct D2 : virtual BASE {
//error, D2 must not have virtual base class.
constexpr D2() : BASE(), mem(55) { }
private:
int mem;
};
struct D3 : B2 {
//error, D3 must not be a function try block.
constexpr D3(int) try : B2(), mem(55) { } catch(int) { }
//error, illegal statement is in body.
constexpr D3(char) : B2(), mem(55) { mem = 55; }
//error, initializer for mem is not a constant expression.
constexpr D3(double) : B2(), mem(i) { }
//error, implicit conversion is not constexpr.
constexpr D3(const D1 &d) : B2(), mem(d) { }
//error, parameter NL is a non-literal type.
constexpr D3(NL) : B2(), mem(55) { }
private:
int mem;
};