C++ C++;一个引用的多次转发:先复制,然后移动

C++ C++;一个引用的多次转发:先复制,然后移动,c++,c++11,operator-precedence,stdtuple,list-initialization,C++,C++11,Operator Precedence,Stdtuple,List Initialization,考虑以下代码,其中同一引用被转发两次到基类,并在基类中用于构造元组: template<typename ... Ts> struct Base { template<typename ... _Ts> Base(_Ts&& ... ts) : tup{std::forward<_Ts>(ts) ...} {} std::tuple <Ts ...> tup; }; template<typenam

考虑以下代码,其中同一引用被转发两次到基类,并在基类中用于构造元组:

template<typename ... Ts>
struct Base
{
    template<typename ... _Ts>
    Base(_Ts&& ... ts) : tup{std::forward<_Ts>(ts) ...} {}

    std::tuple <Ts ...> tup;
};

template<typename T>
struct Derived : public Base<T, T>
{
    template<typename _T>
    Derived(_T&& t) : Base<T, T>{t, std::forward<_T>(t)} {}
};
这是。(gcc编译器在这方面显然有过一次bug,但已经两年了,应该不再是问题了。)

问题:

  • 我在这里的实施或假设上哪里错了
  • 如何修复上述代码,使其按预期运行:先复制,然后移动

    • 我不确定对象初始化的操作顺序是否重要。由于完美的转发,在调用
      std::tuple
      构造函数之前,实际上不会进行复制或移动(即只传递左值引用和右值引用)。在这一点上,它取决于
      std::tuple
      的实现细节

      考虑是否使用了以下
      my\u tup
      struct而不是
      std::tuple

      template<typename T1, typename T2>
      struct my_tup
      {
          template <typename A, typename B>
          my_tup(A&& a, B&& b) 
              : t1(std::forward<A>(a)), t2(std::forward<B>(b))
          {
          }
      
          T1 t1;
          T2 t2;
      };
      
      模板
      结构我的图
      {
      模板
      我的房间(A&A,B&B)
      :t1(std::forward)。但如果您有:

      template<typename T1, typename T2>
      struct my_tup
      {
          template <typename A, typename B>
          my_tup(A&& a, B&& b) 
              : t2(std::forward<B>(b)), t1(std::forward<A>(a))
          {
          }
      
          T2 t2;
          T1 t1;
      };
      
      模板
      结构我的图
      {
      模板
      我的房间(A&A,B&B)
      :t2(std::forward(b)),t1(std::forward)


      很可能是由于变量模板的扩展方式,
      std::tuple
      必须以从右到左的方式处理参数。我不确定这是依赖于实现还是在规范中指定的。

      您应该显式复制,否则您将传递一个引用,该引用稍后将由copy使用(但别名可能已被移动):

      模板
      结构派生:公共基
      {
      模板
      派生(T&&T):基{T(T),std::forward(T)}{
      };
      

      任何以下划线开头,后跟大写字母的符号都是为实现保留的;将
      \u T
      \u Ts
      更改为其他符号。很好的技巧:这应该有效(函数的参数在将结果传递给构造函数之前被调用,std::forward只是一个强制转换)谢谢,我想这就是答案。评估并不意味着构造。标准中相应的元组构造约束似乎不存在。另请参见其中的说明,元组构造中没有标准顺序。
      template<typename T1, typename T2>
      struct my_tup
      {
          template <typename A, typename B>
          my_tup(A&& a, B&& b) 
              : t2(std::forward<B>(b)), t1(std::forward<A>(a))
          {
          }
      
          T2 t2;
          T1 t1;
      };
      
      template<typename U>
      struct Derived : public Base<U, U>
      {
          template<typename T>
          Derived(T&& t) : Base<U, U>{T(t), std::forward<T>(t)} {}
      };