构造函数初始值设定项列表中未知长度的数组

时间:2019-07-03 12:51:42

标签: c++ c++11 initialization

我有一个带有成员数组的类。长度是一个常数,但是直到编译时才知道该常数(在我的实际代码中,对于不同的编译目标,此常数的定义有所不同)。数组的类型是没有默认构造函数的类。

#define CONSTANT 2

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

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

在此示例中,我可以使用初始化列表设置_member。但是,如果COSNTANT的值更改,则必须更改该初始化程序列表。

理论上,将DemoClass更改为具有默认构造函数,该默认构造函数使用参数0调用另一个构造函数将很适合我的情况,因为我将始终使用以下方式调用Data构造函数0。但是,我无法更改DemoClass,因为它在外部库中。

我考虑过的一种解决方案是创建以下类:

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

这可行,但似乎有点复杂。有没有更简单的方法来初始化此数组?

3 个答案:

答案 0 :(得分:3)

我找到了您的问题here的答案。因此,在您的情况下,应按以下方式应用此解决方案:

#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
    }
};

然后,您的_member是静态分配的固定大小的数组。不过,这种方法有点复杂,因此也许有人可以提供更清洁的解决方案。

答案 1 :(得分:2)

一个简单的解决方案是使用std::vector。显然,这样做确实存在引入动态分配的缺点:

std::vector<Data> _member;

DemoClass() : _member(CONSTANT, Data(0))

如果您使用原始字符存储的成员(具有足够的大小和对齐方式)并使用placement-new构造元素,则可以在不进行动态分配的情况下进行相同操作。这也是向量的作用。但是,这有点复杂:

class DemoClass {
private:
    std::aligned_storage_t<sizeof(Data), alignof(Data)> storage[CONSTANT];
public:
    DemoClass()
    {
        std::uninitialized_fill(begin(), end(), Data(0));
    }

    Data* begin() {
        return std::launder(reinterpret_cast<Data*>(std::begin(storage)));
    }

    Data* end() {
        return std::launder(reinterpret_cast<Data*>(std::end(storage)));
    }

    ~DemoClass() {
        for(Data& d : *this)
            d.~Data();
    }
};

答案 2 :(得分:1)

编写示例代码的方式并非一帆风顺,因为您已经在Data上创建了2个构造函数。

,但是,如果您将Data更改为以下内容(请记住:这只是为了避免对调用哪个构造函数产生任何混淆-您未提供完整的代码):

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

现在,您可以使用空括号将其初始化:

_member{ }

这将确保所有成员都已初始化。

另外,我建议使用std::array<Data, CONSTANT>而不是c数组。