如何将完全转发与大括号括起来的初始化式结合起来
How to combine perfect forwarding with brace enclosed initializers
下面的代码编译为:
pair <pair<int,int>,unique_ptr<int>> t({0,0}, unique_ptr<int>());
除此之外:
tuple<pair<int,int>,unique_ptr<int>> t(make_pair(0,0), unique_ptr<int>());
但是这个没有:
tuple<pair<int,int>,unique_ptr<int>> t({0,0}, unique_ptr<int>());
原因是第三个调用tuple(const Types&...)
,但这似乎是一个任意的限制。
是c++ 11无法表达这与可变模板或它是可能的?
这是可能的,但不是微不足道的。为了实现这一点,包含N
参数的元组必须支持2^N
构造函数,即每个T
的T&&
和T const&
的所有组合。
我们要做的是混合这些2^N
构造函数,这可以使用继承来完成。由于基类的构造函数只能通过using
显式地提供,因此只能添加固定数量的基类的构造函数,因此必须使用递归。
一种方法是从0
计数到2^N
,如果第i位为1,则将第i位参数设置为const-ref,否则为右值。在2^N
基类中这样做,其中每个基类向其直接基类添加一个构造函数。
namespace detail {
// A bitlist holds N powers of two: 1, 2, 4, 8, 16, ...
template <std::size_t... i> struct bitlist { using type = bitlist; };
template <std::size_t N, typename=bitlist<>>
struct make_bitlist;
template <std::size_t N, std::size_t... i>
struct make_bitlist<N, bitlist<i...>>
: make_bitlist<N-1, bitlist<0,1+i...>> {};
template <std::size_t... i> struct make_bitlist<0, bitlist<i...>>
: bitlist<(1<<i)...> {};
struct forward_tag {}; // internal struct that nobody else should use
// if T is a reference, some constructors may be defined twice, so use a non-accessible type.
template <bool B, typename T>
using const_if_set = typename std::conditional<B,
typename std::conditional<std::is_reference<T>::value, forward_tag, T const&>::type, T&&>::type;
// Our helper class. Each tuple_constructor is derived from N-1 others
// each providing one constructor. N shall equal (1<<sizeof...(T))-1
template <std::size_t N, typename L, typename... T> struct tuple_constructor;
template <std::size_t N, std::size_t... I, typename... T>
struct tuple_constructor<N, bitlist<I...>, T...>
: tuple_constructor<N-1, bitlist<I...>, T...>
{ // inherit base constructors
using tuple_constructor<N-1, bitlist<I...>, T...>::tuple_constructor;
tuple_constructor(const_if_set<(N & I), T>... t)
: tuple_constructor<N-1, bitlist<I...>, T...>
(forward_tag{}, std::forward<const_if_set<(N & I), T>>(t)...) {}
};
// base case: N=0, we finally derive from std::tuple<T...>
template <std::size_t... I, typename... T>
struct tuple_constructor<0, bitlist<I...>, T...> : std::tuple<T...> {
tuple_constructor(T&&... t)
: tuple_constructor(forward_tag{}, std::forward<T&&>(t)...) {}
// All constructor calls are forwarded to this one
template <typename... T2>
tuple_constructor(forward_tag, T2&&... t2)
: std::tuple<T...>(std::forward<T2>(t2)...) {}
};
// Convenience using for N=2^n, bitlist=1,2,4,...,2^n where n = sizeof...(T)
template <typename... T>
using better_tuple_base = tuple_constructor
< (1<<sizeof...(T)) - 1, typename make_bitlist<sizeof...(T)>::type, T... >;
}
template <typename... T> struct better_tuple : detail::better_tuple_base<T...> {
using typename detail::better_tuple_base<T...>::tuple_constructor;
};
Live at LWS
但是要注意,这不能很好地扩展到大元组,并且会显著增加编译时间。在我看来,这是语言的限制。
相关文章:
- 是否可以初始化不可复制类型的成员变量(或基类)
- C++使用整数的压缩数组初始化对象
- C++初始化基类
- 多成员Constexpr结构初始化
- Qt并发错误:数组初始化需要大括号括起来的初始值设定项列表
- 从大括号括起来的列表进行数组初始化C++很奇怪
- 从类型为"<大括号括起来的初始值设定项列表>"的类型非常量引用的无效初始化
- 从大括号括起来的初始值设定项列表进行的Lvalue引用初始化无法编译
- 为什么在使用初始化语法时不调用转换运算符,为什么 clang 错误消息看起来是错误的
- 为什么我必须用括号括起来初始化表达式(逗号表达式)?
- 正在使用大括号括起来的初始值设定项列表初始化结构向量
- 用大括号括起来的初始化列表初始化结构体时出错
- c++ 11g++使用大括号括起来的初始化列表
- 多维用大括号括起来的多向量初始化列表
- 是否有可能将统一初始化和构造函数结合起来?
- c++错误:在'{'标记之前不允许使用大括号括起来的初始化式
- 是否可以为容器的容器使用大括号括起来的初始化列表?
- 如何将完全转发与大括号括起来的初始化式结合起来
- 用大括号括起来的初始值设定项列表初始化类
- 导致初始化的类成员变量在方法调用中变为(或看起来)未初始化的原因