构造函数初始化器列表中未知长度的数组

Array of unknown length in constructor initializer list

本文关键字:数组 未知 初始化 列表 构造函数      更新时间:2023-10-16

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

#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参数的构造函数将对我的情况有用,因为我总是将使用0调用Data构造函数。但是,我无法更改DemoClass,因为它在外部库中。

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

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

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

我在这里找到了您问题的答案。因此,在您的情况下,应像这样应用此解决方案:

#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是静态分配的固定尺寸数组。但是,这种方法有点复杂,所以也许有人可以提供更清洁的解决方案。

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

std::vector<Data> _member;
DemoClass() : _member(CONSTANT, Data(0))

IT 如果使用原始字符存储的成员(具有足够的尺寸和对齐方式(,并且可以使用放置新构建元素,则可以在没有动态分配的情况下进行相同的操作。这也是向量所做的。但是有点复杂:

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();
    }
};

您编写示例代码的方式,它并不简单,因为您已经在Data上创建了2个构造函数。

但是,如果将Data更改为以下(请记住:这只是为了避免对哪个构造函数的混淆 - 您没有提供完整的代码(:

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

现在,您可以用空的支架来支撑优势:

_member{ }

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

附加我建议使用std::array<Data, CONSTANT>代替C数组。