结合以前的文章中的一些想法,这是一个甚至对嵌套结构也适用的解决方案(已在GCC4.6中进行了测试):
template <typename T, typename ...Args>
std::array<T, sizeof...(Args) + 1> make_array(T && t, Args &&... args)
{
static_assert(all_same<T, Args...>::value, "make_array() requires all arguments to be of the same type."); // edited in
return std::array<T, sizeof...(Args) + 1>{ std::forward<T>(t), std::forward<Args>(args)...};
}
奇怪的是,不能将返回值作为右值引用,这不适用于嵌套构造。无论如何,这是一个测试:
auto q = make_array(make_array(make_array(std::string("Cat1"), std::string("Dog1")), make_array(std::string("Mouse1"), std::string("Rat1"))),
make_array(make_array(std::string("Cat2"), std::string("Dog2")), make_array(std::string("Mouse2"), std::string("Rat2"))),
make_array(make_array(std::string("Cat3"), std::string("Dog3")), make_array(std::string("Mouse3"), std::string("Rat3"))),
make_array(make_array(std::string("Cat4"), std::string("Dog4")), make_array(std::string("Mouse4"), std::string("Rat4")))
);
std::cout << q << std::endl;
// produces: [[[Cat1, Dog1], [Mouse1, Rat1]], [[Cat2, Dog2], [Mouse2, Rat2]], [[Cat3, Dog3], [Mouse3, Rat3]], [[Cat4, Dog4], [Mouse4, Rat4]]]
(对于最后的输出,我正在使用我的漂亮打印机。)
实际上,让我们提高此构造的类型安全性。我们绝对需要所有类型都相同。一种方法是添加一个静态断言,该断言我已在上面进行了编辑。另一种方法是仅make_array
在类型相同时启用,如下所示:
template <typename T, typename ...Args>
typename std::enable_if<all_same<T, Args...>::value, std::array<T, sizeof...(Args) + 1>>::type
make_array(T && t, Args &&... args)
{
return std::array<T, sizeof...(Args) + 1> { std::forward<T>(t), std::forward<Args>(args)...};
}
无论哪种方式,您都需要可变参数all_same<Args...>
类型特征。这是从归纳std::is_same<S, T>
(注意,衰减是很重要的,允许混合T
,T&
,T const &
等):
template <typename ...Args> struct all_same { static const bool value = false; };
template <typename S, typename T, typename ...Args> struct all_same<S, T, Args...>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value && all_same<T, Args...>::value;
};
template <typename S, typename T> struct all_same<S, T>
{
static const bool value = std::is_same<typename std::decay<S>::type, typename std::decay<T>::type>::value;
};
template <typename T> struct all_same<T> { static const bool value = true; };
请注意,make_array()
按临时副本返回,允许编译器(具有足够的优化标志!)将其视为右值或以其他方式优化,并且std::array
是聚合类型,因此编译器可以自由选择最佳的构造方法。
最后,请注意,make_array
设置初始值设定项时,您无法避免复制/移动构造。因此std::array<Foo,2> x{Foo(1), Foo(2)};
没有复制/移动,但是auto x = make_array(Foo(1), Foo(2));
在将参数转发到时有两个复制/移动make_array
。我认为您无法对此进行改进,因为您无法将可变参数的初始化程序列表按词法传递给帮助程序并推导类型和大小-如果预处理器具有sizeof...
可变参数的函数,也许可以这样做,但不能在核心语言中。