如何将完全转发与大括号括起来的初始化式结合起来

How to combine perfect forwarding with brace enclosed initializers

本文关键字:起来 初始化 结合 转发      更新时间:2023-10-16

下面的代码编译为:

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构造函数,即每个TT&&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

但是要注意,这不能很好地扩展到大元组,并且会显著增加编译时间。在我看来,这是语言的限制。