Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Compiler error when initializing constexpr static class member

I've declared a class in the following way

class A
{
    struct B
    {
        constexpr
        B(uint8_t _a, uint8_t _b) :
            a(_a),
            b(_b)
        {}

        bool operator==(const B& rhs) const
        {
            if((a == rhs.a)&&
               (b == rhs.b))
            {
                return true;
            }
            return false;
        }

        uint8_t a;
        uint8_t b;
    };

    constexpr static B b {B(0x00, 0x00)};

};

But g++ says

error: field initializer is not constant

Can't figure out where I'm wrong.

like image 352
niebelung Avatar asked Jul 02 '14 09:07

niebelung


2 Answers

Clang is more helpful:

27 : error: constexpr variable 'b' must be initialized by a constant expression
constexpr static B b {B(0x00, 0x00)};
                   ^~~~~~~~~~~~~~~~
27 : note: undefined constructor 'B' cannot be used in a constant expression
constexpr static B b {B(0x00, 0x00)};
                      ^
8 : note: declared here
B(uint8_t _a, uint8_t _b) :
^

Within a brace-or-equal-initializer of a member variable, constructors (including constructors of nested classes) are considered undefined; this is because it is legitimate for a constructor to refer to the values of member variables, so the member variables must be defined first even if they are lexically later in the file:

struct A {
  struct B { int i; constexpr B(): i{j} {} };
  constexpr static int j = 99;
};

The workaround is to place B outside A, or perhaps within a base class.

like image 178
ecatmur Avatar answered Sep 28 '22 09:09

ecatmur


This will work:

#include <cstdint>
#include <iostream>

class A
{
    struct B
    {
        bool operator==(const B& rhs) const
        {
            if((a == rhs.a)&&
               (b == rhs.b))
            {
                return true;
            }
            return false;
        }

        uint8_t a;
        uint8_t b;
    };

  public:
    constexpr static B b {0x61, 0x62};

};

int main() {
    std::cout << '{' << A::b.a << ',' << A::b.b << '}' << std::endl;
}

Removing the constructor from the struct will allow the braces initializer to work. This won't really help you if you were planning on doing something funky in the constructor.

like image 43
Matt Clarkson Avatar answered Sep 28 '22 08:09

Matt Clarkson