c++constexprstatic-assert

constexpr: Why my expression is not a constant expression?


I want to define a buffer at compile-time and check its size with a static_assert:

struct Buffer{
    int* array;
    size_t size;
};

template<typename T, int size>
struct ConstArray{
  T arr[size];

  constexpr ConstArray(T t[size]):arr(){
    for(int e = 0; e < size; e++)
      arr[e] = t[e];
  }

  constexpr const T& operator[](size_t e)const{
    return &arr[e];
  }
};

struct A {
    Buffer* b;
};

constexpr ConstArray<A, 1> a_maps(    
    (A[]){(Buffer[]){(int[]){0,1,2}, 3}} // error: constexpr variable 'a_maps' must be initialized by a constant expression 
);

int main()
{
    static_assert(a_maps[0].b->size == 3, "NOP"); // error: static assertion expression is not an integral constant expression
    return 0;
}

Any advice to make this approach viable?

https://godbolt.org/z/W1xGd4n5b


Solution

  • (A[]){/*...*/} and (int[]){0,1,2} are not valid standard-C++ syntax. Your compiler is only supporting them as an extension called compound literals, which comes from C.

    Because the standard doesn't know anything about this syntax, it is mostly pointless to argue whether or not your code should be a constant expression. It will be completely up to the compiler.

    It is not a good idea to use them in C++ code because compound literals look like they are similar to T{...} syntax in C++, but in C they actually behave very differently. They have a different storage duration, lifetime, and value category. So immediately, it isn't even obvious whether the C++ extension will behave like the C syntax in C, or more similar to the C++ constructs. It is necessary to verify in the compiler documentation to not accidentally cause Undefined Behavior.

    Compile with -pedantic-errors to get GCC and Clang to complain about this extension in C++ mode (or -pedantic if you only want warnings).


    If you replace the compound literals with constexpr-qualified array variables, then it should pass the assertion.