问题
I read this (incredibly well written) article about Forwarding Reference in C++11 by Scott Meyers.
Now, focus on this part of the article:
template <class... Args> void emplace_back(Args&&... args); // deduced parameter types ⇒ type deduction; ... // && ≡ universal references
So, in contrast with other cases, the ellipses doesn't make the &&
an rvalue reference, but it's still universal references.
From what I've understood, when we have universal references, we can call the function passing both rvalue and lvalues (wow, so cool!)
Now, I've implemented this function:
template <typename ReturnType, typename... Args>
ReturnType callFunction(MemFunc<ReturnType, Args...> memFunc, Args&& ... args) { ...
So (using the same logic of the previous example), &&
means forwarding references.
But if I try to make this call:
typedef vector<double> vecD;
vecD vec;
mem.callFunction<vecD, vecD>(sortFunc, vec);
The compiler is going to complain with You cannot bind an lvalue to an rvalue reference
Why this happens?
THE WHOLE CODE:
#include <functional>
#include <vector>
using namespace std;
struct MultiMemoizator {
template <typename ReturnType, typename... Args>
ReturnType callFunction(std::function<ReturnType(Args...)> memFunc, Args&&... args) {
}
};
typedef vector<double> vecD;
vecD sort_vec (vecD const& vec) {
return vec;
}
int main()
{
vecD vec;
std::function<vecD(vecD)> sortFunc(sort_vec);
MultiMemoizator mem;
mem.callFunction<vecD, vecD>(sortFunc, vec);
}
回答1:
So first off, please use the "forwarding reference" instead of "universal reference". It better represents what it is and what its intended use is.
The first thing to be aware of is that not every &&
is a forwarding reference. It can also be an rvalue reference.
In simple terms T&&
is a forwarding reference if and only if:
T
is a simple (simple as shown next) type (so for instancevector<int>&&
orvector<T>&&
is not a forwarding reference).- and
T
is deduced.
In your example Args
is not deduced. That is because you explicitly specify the function template argument Args
when you call it:
mem.callFunction<vecD, vecD>(sortFunc, vec);
^~~~
Let's work with something simpler to better understand:
Lets set up the scene:
struct X {};
template <class T>
auto foo(T&& p) {}
In the next 2 calls, we have forwarding references:
X x;
foo(x);
foo(X{});
In the first, T
will be deduced as X&
and by collapsing rules: X& &&
becomes X&
, therefore we have an lvalue reference. As you would expect.
In the second, T
will be deduced as X
and by collapsing rules X &&
becomes X&&
, therefore we have an rvalue reference.
But when you call it like this:
foo<X>(x);
T
is no longer deduced. You basically say let T
be X
. So if T
is X
then T &&
is X&&
, and you have the error: p
whose type is now X&&
cannot bind to an lvalue.
Holt also added:
Also note that because of the declaration of sortFunc, this would not work even if you did not specify the function template arguments explicitely.
I tend to agree with him, but I would need to investigate further to be sure of this.
来源:https://stackoverflow.com/questions/36842291/c-confusion-about-forwarding-reference