Why does a templated rvalue reference accept lvalues?

前端 未结 1 615
臣服心动
臣服心动 2021-01-14 04:11

I saw the usage of something like

#include 
#include 
using namespace std;

template
void Foo(FN&&a         


        
相关标签:
1条回答
  • 2021-01-14 04:54

    The rules for deduction of T&& are tricky.

    They where designed to make a deduced T&& a "forwarding reference" (or "universal reference").

    First, reference collapsing. Suppose you have an unknown type X. For now X is not deduced.

    Then if we examine variables of the following type:

    typedef X x0;
    typedef X& x1;
    typedef X const& x2;
    typedef X&& x3;
    

    and we set X to be one of int, int&, int const& and int&&, we get:

    X is --->  int         int&      int const&      int&&
    X          int         int&      int const&      int&&
    X&         int&        int&      int const&      int&
    X const&   int const&  int&      int const&      int&
    X&&        int&&       int&      int const&      int&&
    

    live example.

    The next bit comes with the deduction rules. If you pass X& to T&& in a deduced context, T is deduced to be X&. This causes T&& to become X& by the above reference collapsing rules. Similar things happen for X const&.

    If you pass X&& to T&&, it deduces T to be X. T&& becomes X&& as well.

    Between the two of them, in a deduced context, template<class T> void foo(T&&t) is a universal reference (well, now called a forwarding reference).

    You can recover the r/l value category of t with std::forward<T>(t), hence the name forwarding reference.

    This allows one template to process both l and r values, and use std::forward and similar machinery to behave slightly differently, if you want.

    Only processing rvalues requires extra work: you have to use SFINAE or another overload (possibly with =delete). Only processing lvalues is easy (just deduce with T&).

    0 讨论(0)
提交回复
热议问题