结合之前帖子的一些想法,这里提供了一个解决方案,即使是嵌套结构也可以使用(在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()
返回一个临时副本,编译器(使用足够的优化标志!)可以将其视为rvalue或以其他方式进行优化,并且
std::array
是一个聚合类型,因此编译器可以自由选择最佳的构造方法。
最后,请注意,当
make_array
设置初始化程序时,您无法避免复制/移动构造。因此,
std::array<Foo,2> x{Foo(1), Foo(2)};
没有复制/移动,但是
auto x = make_array(Foo(1), Foo(2));
有两个复制/移动,因为参数被转发到
make_array
。我认为您无法改进这一点,因为您无法在语法上将可变数量的初始化列表传递给帮助程序并推断类型和大小--如果预处理器对于可变参数有一个
sizeof...
函数,则可能可以完成,但不能在核心语言中完成。