Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trouble with constexpr member variables, nested classes

Tags:

c++

c++11

I'm trying to write a class with multiple static constexpr values of itself; this doesn't seem to be allowed because the constexpr declaration needs the definition of the class which isn't available inside the class declaration. MCV of my first attempt looked like this:

struct A {
    constexpr A(float x) : _x(x) {}
    float _x;

    static constexpr A y = A(1.f);
    // gcc-5.1:
    // error: invalid use of incomplete type 'struct A'
    // static constexpr A y = A(1.f);
    //                             ^
    // msvc-14:
    // error C2027: use of undefined type 'A'
    // note: see declaration of 'A'
    // note: see declaration of 'A'
    // error C2079: 'public: static A const A::y' uses undefined struct 'A'
};

My next attempt was to declare a 'constant' class (with implicit conversion to the data class, not shown here). This seems to work fine:

struct B_constant {
    constexpr B_constant(float x) : _x(x) {}
    float _x;
};

struct B {
    static constexpr B_constant y = B_constant(1.f);
};

But it's a little ugly, so I thought I'd try making the constant class a nested class of the data class, but this does not work:

struct C {
    struct C_constant {
        constexpr C_constant(float x) : _x(x) {}
        float _x;
    };

    static constexpr C_constant y = C_constant(1.f);
    // gcc-5.1:
    // error: 'constexpr C::C_constant::C_constant(float)' called in a constant expression
    // static constexpr C_constant y = C_constant(1.f);
    //                                               ^
    // msvc-14:
    // error C2131: expression did not evaluate to a constant
    // note: failure was caused by call of undefined function or one not declared 'constexpr'
    // note: see usage of 'C::C_constant::C_constant'
};

I noticed that the failure was similar to an error when declaring the constexpr constructor but defining it after it's used in the data class:

struct D_constant {
    constexpr D_constant(float x);
    float _x;
};

struct D {
    static constexpr D_constant y = D_constant(1.f);
    // gcc-5.1:
    // error: 'constexpr D_constant::D_constant(float)' used before its definition
    // static constexpr D_constant y = D_constant(1.f);  
    //                                               ^
    // msvc-14:
    // error C2131: expression did not evaluate to a constant
    // note: failure was caused by call of undefined function or one not declared 'constexpr'
    // note: see usage of 'D::D_constant::D_constant'
};

constexpr D_constant::D_constant(float x) : _x(x) {}

Can anyone shed light on what's going on with the third example? It appears that the compiler cannot locate the definition of the constexpr constructor inside the nested class despite the fact that the nested class declaration is complete. Does anyone know of a better way to accomplish what I'm trying to do?

like image 942
Qartar Avatar asked Oct 19 '25 20:10

Qartar


1 Answers

As stated here:

A class is considered a completely-defined object type (or complete type) at the closing } of the class-specifier. [...] Otherwise it is regarded as incomplete within its own class member-specification.

Where [...] is a list of exceptions that doesn't mention nested classes.

This defines member-specification:

The member-specification in a class definition declares the full set of members of the class; no member can be added elsewhere. Members of a class are data members, member functions, nested types, enumerators, and member templates and specializations thereof. [...]

Therefore, nested classes are considered part of the class specification and cannot be referred until you have a complete type (that is at the closing }, set aside the mentioned exceptions).
Data members are also part of the member specification and at the point of declaration of such a member the class must be considered as incomplete.
Note that by using the name C_constant you are actually using the qualified name C::C_constant, that is part of the definition of C. The fact that you can refer to it with a shorter identifier from within C does not alter its nature.

like image 91
skypjack Avatar answered Oct 22 '25 11:10

skypjack



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!