std::initializer_list的编译时串联



我想写一些代码,如下所示:

using int_list_t = std::initializer_list<int>;
struct ThreeDimensionalBox {
static constexpr int_list_t kDims = {1, 2, 3};
};
struct FourDimensionalBox {
static constexpr int_list_t kDims = {4, 5, 6, 7};
};
template<typename Box1, typename Box2>
struct CombinedBox {
static constexpr int_list_t kDims = Box1::kDims + Box2::kDims;  // error
};
using SevenDimensionalBox = CombinedBox<ThreeDimensionalBox, FourDimensionalBox>;

是否有某种方法可以修复CombinedBox的实现,从而使SevenDimensionalBox::kDims有效地绑定到{1, 2, 3, 4, 5, 6, 7}

我知道我可以用一个带有可变int模板参数列表的自定义模板类来替换std::initializer_list<int>,通过标准的元编程递归技术可以有效地实现串联。我只是想知道是否存在只使用std::initializer_list的解决方案。

std::initializer_list只能初始化为空、包含大括号的元素列表或通过复制进行初始化。

然而,即使使用复制构造,std::initializer_list引用的实际数组的生存期也由原始std::initializer_list对象的生存期决定,该对象由带大括号的元素列表初始化。换句话说,复制std::initializer_list不会复制阵列或延长其寿命。

因此,不可能连接std::initializer_lists。它们不应用作容器。std::initializer_list主要应仅用作函数参数,作为将未指定大小的元素的大括号列表传递给函数的一种轻量级方式,以便函数进一步处理这些元素。

您可能想要std::array。类似这样的东西(需要C++17,但不需要C++20):

struct ThreeDimensionalBox {
static constexpr auto kDims = std::array{1, 2, 3};
};
struct FourDimensionalBox {
static constexpr auto kDims = std::array{4, 5, 6, 7};
};
template<typename T, std::size_t N, std::size_t M>
constexpr auto concat_arrays(const std::array<T, N>& a, const std::array<T, M>& b) {
// assumes `T` is default-constructible
std::array<T, N+M> r;
std::copy(std::begin(a), std::end(a), std::begin(r));
std::copy(std::begin(b), std::end(b), std::begin(r)+N);
return r;
}
template<typename Box1, typename Box2>
struct CombinedBox {
static constexpr auto kDims = concat_arrays(Box1::kDims, Box2::kDims);
};
using SevenDimensionalBox = CombinedBox<ThreeDimensionalBox, FourDimensionalBox>;

std::initializer_list的目的只有一个:在一个支持的init列表({}中的东西)用于初始化对象的范围内,成为一个初始化对象的工具。这种类型的一切都是为了这个目的而构建的,它有一堆防火墙,基本上可以防止你用它做任何其他事情

其中最重要的是initializer_list实际上并没有存储任何东西;它引用存储在其他地方的值数组(即创建它的{}的引用)。由于它不存储数组,而且它们只是根据{}语法结构构建的,因此不能为它们提供一个可引用的数组。他们只能通过复制从现有的initializer_list对象中获得数组,而该对象只能从{}或现有initializer_list中获得一个数组,后者只能从。。。好吧,你明白了。

如果您需要进行编译时数组操作,std::array是一个更好的工具。如果您想连接两个支撑的init列表,并使用结果初始化某个对象。。。你不能那样做。

不要尝试将initializer_list用作快速且脏的数组类型。仅用于初始化对象。

相关内容

最新更新