Stefan
Stefan

Reputation: 1309

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).

Upvotes: 0

Views: 55

Answers (3)

Pepijn Kramer
Pepijn Kramer

Reputation: 13076

I would do it like this a private lambda to calculate the values, and then initialze from that.

#include <array>

struct Spec
{
    int val;
    double otherVal;
};

class Test
{
private:
    static constexpr auto init_array = []
    {
        std::array<Spec, 2> array{};
        array[0] = { 1, 3.56 };
        array[1] = { 1, 3.56 };
        return array;
    };

public:
    static constexpr auto myArray{ init_array() };
};

int main()
{
    static_assert(Test::myArray[0].val == 1);
    return 0;
}

Upvotes: 1

Eyal Kamitchi
Eyal Kamitchi

Reputation: 195

you can also initialize it outside the class definition.

// Test.hpp
std::array<Spec, 2> Test::myArray = Test::make_init_data();

Upvotes: 0

Jarod42
Jarod42

Reputation: 218088

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

Upvotes: 4

Related Questions