Reputation: 1612
pass()
reference argument and pass it to reference
, however a rvalue argument actually called the reference(int&)
instead of reference(int &&)
, here is my code snippet:
#include <iostream>
#include <utility>
void reference(int& v) {
std::cout << "lvalue" << std::endl;
}
void reference(int&& v) {
std::cout << "rvalue" << std::endl;
}
template <typename T>
void pass(T&& v) {
reference(v);
}
int main() {
std::cout << "rvalue pass:";
pass(1);
std::cout << "lvalue pass:";
int p = 1;
pass(p);
return 0;
}
the output is:
rvalue pass:lvalue
lvalue pass:lvalue
For p
it is easy to understand according to reference collapsing rule, but why the template function pass v
to reference()
as lvalue?
Upvotes: 7
Views: 946
Reputation: 21576
template <typename T>
void pass(T&& v) {
reference(v);
}
You are using a Forwarding reference here quite alright, but the fact that there is now a name v
, it's considered an lvalue
to an rvalue reference.
Simply put, anything that has a name is an lvalue
. This is why Perfect Forwarding is needed, to get full semantics, use std::forward
template <typename T>
void pass(T&& v) {
reference(std::forward<T>(v));
}
What std::forward<T>
does is simply to do something like this
template <typename T>
void pass(T&& v) {
reference(static_cast<T&&>(v));
}
See this;
Upvotes: 8
Reputation: 48938
Why the template function pass
v
toreference()
as lvalue?
That's because v
is an lvalue. Wait, what? v
is an rvalue reference. The important thing is that it is a reference, and thus an lvalue. It doesn't matter that it only binds to rvalues.
If you want to keep the value category, you will have to do perfect forwarding. Perfect forwarding means that if you pass an rvalue (like in your case), the function will be called with an rvalue (instead of an lvalue):
template <typename T>
void pass(T&& v) {
reference(std::forward<T>(v)); //forward 'v' to 'reference'
}
Upvotes: 7