Warm tip: This article is reproduced from stackoverflow.com, please click
c++ c++11 initialization

Array of unknown length in constructor initializer list

发布于 2020-03-27 10:18:02

I have a class with a member array. The length is a constant, but this constant is not known until compile time (In my actual code, this constant is defined differently for different compilation targets). The type of the array is a class with no default constructor.

#define CONSTANT 2

class Data {
public:
    Data(int number){}
};

class DemoClass {
private:
    Data _member[CONSTANT];
public:
    DemoClass():
        _member{
            Data(0),
            Data(0)
        }
    {
        // stuff
    }
};

In this example, I can set _member using the initializer list. However, if the value of COSNTANT changes, I have to change that initializer list.

In theory, changing DemoClass to have a default constructor that calls the other constructor with an argument of 0 would work for my case, because I will always call the Data constructor with 0. However, I cannot change DemoClass because it is in an external library.

One solution I've considered is creating the following class:

class CustomData : public Data {
public:
    CustomData() : Data(0){}
};

This works, but it seems a bit complicated. Is there a simpler way to initialize this array?

Questioner
ItsTimmy
Viewed
130
pptaszni 2019-07-03 21:34

I found the answer to your problem here. So, in your case this solution should be applied like that:

#include <utility>
#include <array>

#define CONSTANT 2

class Data {
public:
    Data(int number){}
};

template<typename T, size_t...Ix, typename... Args>
std::array<T, sizeof...(Ix)> repeat(std::index_sequence<Ix...>, Args &&... args) {
   return {{((void)Ix, T(args...))...}};
}

template<typename T, size_t N>
class initialized_array: public std::array<T, N> {
public:
    template<typename... Args>
    initialized_array(Args &&... args)
        : std::array<T, N>(repeat<T>(std::make_index_sequence<N>(), std::forward<Args>(args)...)) {}
};

class DemoClass {
private:
    initialized_array<Data, CONSTANT> _member;
public:
    DemoClass():
        _member(1234)
    {
        // stuff
    }
};

Then your _member is statically allocated fixed size array. That approach is a bit complicated though, so maybe someone can provide a cleaner solution.