Search code examples
c++classstaticconstexprcompile-time-constant

Using a `constexpr static` function defined in a class to initialize a member of the same class


I am a little new to C++ and learning the language. Right now I'm using C++17 and G++.

I'm trying to initialize an array of structs at compile time. I want to explicitly specify the array indexes in which my initial data goes which makes the process much less error prone. For the indexes I'm going to use integer-aliasses, but for the sake of simplicitly I left the alliases out in the example.

I found that this approach could work:

#include <array>

struct Spec
{
    int val;
    double otherVal;
};

constexpr static std::array<Spec, 2> make_init_data()
{
    std::array<Spec, 2> array{};
    array[0] = {1, 3.56};
    array[1] = {1, 3.56};
    return array;
};

constexpr static std::array<Spec, 2> myArray = make_init_data();

This does compile, and myArray is populated.

However, I want myArray to be a class member. So I modified my example to be:

#include <array>

struct Spec
{
    int val;
    double otherVal;
};

class Test
{
    constexpr static std::array<Spec, 2> make_init_data()
    {
        std::array<Spec, 2> array{};
        array[0] = {1, 3.56};
        array[1] = {1, 3.56};
        return array;
    };

    constexpr static std::array<Spec, 2> myArray = make_init_data();
};

Which gives me the following error:

Test.h:19:66: error: 'static constexpr std::array<Spec, 2> Test::make_init_data()' called in a constant expression before its definition is complete
 19 |     constexpr static std::array<Spec, 2> myArray = make_init_data();
    |

I understand that the class definition is not yet complete, and that therefore the constexpr make_init_data cannot be evaluated yet. I can simply put it outside the class definition, but I need many classes doing this. To avoid a lot of cluttering, scrolling and searching, now and in the future my aim is to to have code which is only relevant for functioanlity inside one class to also be inside this class.

Is there a way to use the constexpr so that my array gets populated at compile time while the array is also class member?

(Another way to populate the array at compile time in a similar way without constexpr would also be fine).


Solution

  • You might do it with lambda directly invoked:

    class Test
    {
        constexpr static std::array<Spec, 2> myArray = [](){
            std::array<Spec, 2> array{};
            array[0] = {1, 3.56};
            array[1] = {1, 3.56};
            return array;
        }();
    };
    

    Demo