Search code examples
c++c++17stdarraystdinitializerlist

Build initializer list for array by repeating n times


I have a std:array something like this:

class MyClass {
private:
    std::array<MyComplexType, 10> myArray;
}

In the constructor, I need to do the following:

MyClass::MyClass() : myArray({
    MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)),
    ... repeated 8 more times...
    MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4))
})

Now, I want the 10 to be a compile-time constant that I can modify without having to copy&paste more (or less) of those initializers. They are all the same, I just need a "repeat n times". Everything up to and including C++17 is fair game.

I am 99.9% certain this should be doable with some template magic, but so far I came up with nothing that worked. Any ideas?

(And if it is impossible with templates, maybe with macros? Though I would hate having to go that direction...)


Solution

  • If you want to use a std::array you are going to need to build a helper function, namely a delegating constructor. Your default constructor will then call the delegate to actually initialize the member. That can look like

    class MyClass {
    public:
        // default c'tor, create sequence of 10 integers
        MyClass() : MyClass(std::make_index_sequence<10>{})
    private:
        // delegate, take a sequence and expand the initializer of myArray sizeof...(Is) times
        template <std::size_t... Is>
        MyClass(std::index_sequence<Is...>) : 
            myArray{ (Is, MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)))... } {}
        std::array<MyComplexType, 10> myArray;
    }
    

    You can instead change myArray to be a vector instead and that would let you simplify the code to

    class MyClass {
    public:
        MyClass() : 
            myData(MyComplexType(func(const_arg1, const_arg2, const_arg3).method(const_arg4)), 10) {}
    private:
        std::vector<MyComplexType> myData;
    }