问题
The distinction between rvalue references and forwarding references was made clear enough in this example by Scott Meyers:
Widget&& var1 = someWidget; // here, “&&” means rvalue reference (1)
auto&& var2 = var1; // here, “&&” does not mean rvalue reference (2)
template<typename T>
void f(std::vector<T>&& param); // here, “&&” means rvalue reference (3)
template<typename T>
void f(T&& param); // here, “&&”does not mean rvalue reference (4)
Essentially the distinction happens when we have a deducible context, hence case (3) explicitly states that we have a vector<...>&&
whereas the T
in case (4) is to be deduced and (after applying reference collapsing rules) categorized in terms of "value category".
But what happens with a bit more complex pattern matching? Take the following case for example :
template <template <class...> class Tuple, class... Ts>
void f(Tuple<Ts...>&& arg)
{
}
What does &&
mean here ?
回答1:
In your last example, arg
is an rvalue reference.
A forwarding reference is an rvalue reference to a cv-unqualified template parameter
and Tuple<Ts...>
is not a template parameter.
(Citation from [temp.deduct.call].)
回答2:
It is a rvalue reference, not a forwarding reference.
The easiest way to be sure is to try to pass an lvalue, if it fails, then it is a rvalue reference, if not, then a forwarding reference:
template<typename... Ts>
struct foo {};
//f function definition
int main() {
foo<int, double> bar;
f(bar); // fails! Cannot bind lvalue to rvalue reference
f(foo<int, double>{}); // ok, rvalue is passed
}
回答3:
The concept forwarding reference is not a standard concept, it is usefull de recognize it when you see it, but if you want to understand and deal with it correctly you must understand reference arithmetics. (I believe Meyer's book has also a chapter about it)
What is behind the concept of a forwarding reference is the reference arithmetic:
- && && = &&
- && & = &
- & && = &
- & & = &
Let's simulate compiler template type deduction with a forwarding reference
template<class T>
void foo(T&&);
//...
const int i=42;
foo(i); // the compiler will defines T = const int &
// T&& = const int & && = const int &
// => the compiler instantiates void foo<const int &>(const int &);
foo(6*7);// the compiler will defines T = int
// T&& = int &&
// the compiler instantiates void foo<int>(int &&);
in such a situation, the instantiation of the template foo can produces
a function wich takes argument by lvalue reference or functions which takes arguments rvalue reference: a forwarding reference is either
a rvalue reference or a lvalue reference, depending on template type deduction. It is named like this, because in such a situation, the parameter shall be passed either as an lvalue or as an xvalue, and this is the job of T&& std::forward<T>(T&& a)
If you declare a function has:
template<class T>
void foo(ATemplateClass<T> && a);
whatever the type deduced for T by the compiler, you'll get a rvalue reference paramater.
来源:https://stackoverflow.com/questions/40819058/is-this-a-forwarding-reference