As we've seen, (member) functions and variables of primitive data types can be
defined using the tt(constexpr) modifier.  What about class-type objects?

Objects of classes are values of class type, and like values of primitive
types they can be defined with the tt(constexpr) specifier. Constant
expression class-type objects must be initialized with constant expression
arguments; the constructor that is actually used must itself have been
declared with the tt(constexpr) modifier. Note again that the tt(constexpr)
constructor's definition must have been seen by the compiler before the
tt(constexpr) object can be constructed:
        verb(
    class ConstExpr
    {
        public:
            constexpr ConstExpr(int x);
    };

    ConstExpr ok{ 7 };              // OK: not declared as constexpr

    constexpr ConstExpr err{ 7 };   // ERROR: constructor's definition
                                    //        not yet seen

    constexpr ConstExpr::ConstExpr(int x)
    {}

    constexpr ConstExpr ok{ 7 };                // OK: definition seen
    constexpr ConstExpr okToo = ConstExpr{ 7 }; // also OK
        )

    A i(constant-expression constructor) has the following characteristics:
    itemization(
    it() it is declared with the tt(constexpr) modifier;
    it() its member initializers only use constant expressions;
    it() its body is empty.
    )

    An object constructed with a constant-expression constructor is called a
        emi(user-defined literal).
    Destructors and copy constructors of user-defined literals must be
trivial.

    The tt(constexpr) characteristic of user-defined literals may or may not
be maintained by its class's members. If a member is not declared with a
tt(constexpr) return value, then using that member does not result in a
constant-expression. If a member em(does) declare a tt(constexpr) return value
then that member's return value is considered a tt(constexpr) if it is by
itself a constant expression function. To maintain its tt(constexpr)
characteristics it can refer to its classes' data members em(only) if its
object has been defined with the tt(constexpr) modifier, as illustrated by the
example:
        verb(
    class Data
    {
        int d_x;

        public:
            constexpr Data(int x)
            :
                d_x(x)
            {}

            int constexpr cMember()
            {
                return d_x;
            }

            int member() const
            {
                return d_x;
            }
    };

    Data d1{ 0 };           // OK, but not a constant expression

    enum e1 {
        ERR = d1.cMember()  // ERROR: cMember(): no constant
    };                      //        expression anymore

    constexpr Data d2{ 0 }; // OK, constant expression

    enum e2 {
        OK = d2.cMember(),  // OK: cMember(): now a constant
                            //                expression
        ERR = d2.member(),  // ERR: member(): not a constant
    };                      //                expression
        )
