c++c++20constexprstdarrayconstexpr-function

error while trying to compile .data() from std::array as a constexpr function in c++20


I was trying to compute an array in compilation time to speed up some functions while i encountered an error which I was unable to resolve with the help of cppreference.

The code boils down to this:

#include <cstddef>
#include <array>

template<typename T, size_t size>
constexpr auto giveArray()
{
    std::array<T, size> arr;
    for(size_t i = 0; i < size; ++i)
        arr[i] = 0;
    return arr;
}

constexpr auto arr = giveArray<int,10>().data();

While compiling with: "$ g++ -std=c++20 code.cpp" on ubuntu i get the error that .data() is not a constexpr function while it definitely is. Why am i getting this error and how it can be fixed while still running this function in compilation time and storing only a pointer, not the std::array object?


Solution

  • To initialize a constexpr variable you need an initializer that is a constant expression. But giveArray<int,10>().data(); is not a constant expression.

    From here :

    A constant expression is either a glvalue core constant expression that refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value satisfies the following constraints:

    • if the value is an object of class type, each non-static data member of reference type refers to an entity that is a permitted result of a constant expression,
    • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a non-immediate function, or a null pointer value,
    • if the value is of pointer-to-member-function type, it does not designate an immediate function, and
    • if the value is an object of class or array type, each subobject satisfies these constraints for the value. An entity is a permitted result of a constant expression if it is an object with static storage duration that either is not a temporary object or is a temporary object whose value satisfies the above constraints, or if it is a non-immediate function.

    The expression giveArray<int,10>().data(); has the value category of prvalue , so it is not a glvalue expression. That means it has to be "a prvalue core constant expression whose value satisfies the following constraints" to be a constant expression. Since the expression evaluates to a pointer type, it has to meet this condition :

    • if the value is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object ([expr.add]), the address of a non-immediate function, or a null pointer value

    In this case, it is none of those things so it is not a constant expression. However, if you change the code to like :

    const auto my_array = giveArray<int,10>();
    constexpr auto arr = my_array.data();
    

    my_array is a global variable, which implies it has static storage duration. data() returns a pointer to that storage, which makes it a constant expression.

    In short, this rule makes it so you can't have a pointer with an invalid pointer value when executing code at compile time.