I'm learning perfect forwarding, and run the example code(listed bellow)
template<typename T>
void show_type(T t){
std::cout << typeid(t).name() << std::endl;
}
template<typename T>
void perfect_forwarding(T &&t){
std::cout << std::boolalpha << "is std::string: " << std::is_same<std::string, T>::value << std::endl;
std::cout << std::boolalpha << "is lval-reference: " << std::is_lvalue_reference<T>::value << std::endl;
std::cout << std::boolalpha << "is rval-reference: " << std::is_rvalue_reference<T>::value << std::endl;
show_type(static_cast<T&&>(t));
}
std::string get_string(){
return "hi world";
}
int main() {
std::string s = "hello world";
perfect_forwarding(s); //call 1
perfect_forwarding(get_string()); //call 2
}
The output is
is std::string: false
is lval-reference: true
is rval-reference: false
Ss
is std::string: true
is lval-reference: false
is rval-reference: false
Ss
And I debug with gdb, find out the two calls to perfect_forwarding() are instantiated as
perfect_forwarding<std::string&>(std::string&) //for call 1
perfect_forwarding<std::string>(std::string&&) //for call 2
My question is
In call 1
, why T was deducted as std::string&, I thought it would be std::string, and T&& should be deducted as std::string&&
In call 2
, I thought T should be deducted as std::string&&
I can't find an article talk about this
When you pass an argument to a function which has a forwarding reference T&&
as a parameter for that argument, one of two things happen:
If the argument is an lvalue (such as s
), T
deduces to an lvalue reference (such as std::string&
).
There are no references to references, so you get reference collapsing.
For instance, T&&
where T = std::string&
appears to be an rvalue reference to an lvalue reference, and this collapses to just std::string&
.
Otherwise, if the argument is an rvalue (such as get_string()
), T
deduces to the type of the expression (std::string
), so T&&
is simply std::string&&
.
See also template deduction rules for a more detailed explanation.
Note that in your GDB inspection of
perfect_forwarding<std::string&>(std::string&)
perfect_forwarding<std::string>(std::string&&)
... what appears between pointy brackets is what T
deduced to,
and what appears between parentheses is what T&&
collapsed to.