Perfect forwarding with class template argument deduction

北城以北 提交于 2019-12-03 07:57:12

The C++ standard defines the term forwarding reference. I suppose universal reference is used as a synonym for this term. [temp.deduct.call]/3

A forwarding reference is an rvalue reference to a cv-unqualified template parameter that does not represent a template parameter of a class template.

This concept only applies to template function argument or template constructor argument. In all other cases, T&& is a rvalue reference. The concept of forwarding reference is only usefull for template argument deduction. Let's consider that in the following examples, all the fonctions and constructors are called with an int argument (independently of its constness and value categories (lvalue/rvalue):

//possibilities of argument deduction, [cv] means any combination of "const" and "volatile": 
//  <"","const","volatile","const volatile">
template<class T> void f(T&);
  //4 possibilities: void f([cv] int&);

template<class T> void f(const T&);
  //2 possibilities: void f(const int&);
                   //void f(const volatile int&);

template<class T> void f(T&&);
  //Forwarding reference, 8 possibilities
            //void f([cv] int&);
            //void f([cv] int&&);

template<class T> void f(const T&&);
  //NOT a forwarding reference because of the const qualifier, 2 possibilities:
            //void f(const int&&);
            //void f(const volatile int&&);

template<class T>
struct S{
    template<class U>
    S(U&&);
      //Forwarding reference, 8 posibilities:
            //void S<X>([cv] int&);
            //void S<X>([cv] int&&);
      //no template argument deduction posible

    S(T&&);
      //NOT a forwarding reference, 1 possibility:
            //void S<X>(X&&);
      //Generated argument deduction:
         //template<class T> S(T&&) -> S<T>;
           //not a forwarding reference because T is a parameter of the template class; 
           //=> 4 possibilities: -> S<[cv] int&&>


    T&& a; //an rvalue reference if T is [cv] int or [cv] int&&,
           //an lvalue reference if T is [cv] int&;
           //This comes from reference colapsing rules: &+&=&; &&+&=&; &&+&&=&&       //(Nota: You may consider that a rvalue reference data member is probably a mistake)
 };

template<class U>
S(U&&) -> S<U&&>;
 //Forwarding reference, 8 possibilities:
 //   S<[cv] int&>;
 //   S<[cv] int&&>;

Using std::forward make sense only inside the body of a function or a constructor if the argument of std::forward can either be a rvalue reference or a lvalue reference, depending on template argument deduction and reference collapsing rules. If std::forward's argument always results in a rvalue reference, std::move is prefered, and if it always results in a lvalue reference, nothing is prefered.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!