The following signatures are declared as std::forward overloads:
template<class T> T&& forward(typename remove_reference<T>::type& arg) noexcept;
template<class T> T&& forward(typename remove_reference<T>::type&& arg) noexcept;
Now, consider the following template function:
template<class T> T&& foo_as_always(T&& t)
{
return std::forward<T>(t);
}
If I write:
int i = 0;
foo_as_always(i);
Then this is how the compiler instantiates foo_as_always with T = int&:
int& foo_as_always(int& t)
{
// Does it call the first signature of std::forward(int&)
return std::forward<int&>(t);
}
And if I write:
foo_as_always(0);
Then the compiler instantiates foo_as_always with T = int:
int&& foo_as_always(int&& t)
{
// Does it call the second signature of std::forward(int&&)?
return std::forward<int>(t);
}
In both cases, the t variable is l-value in any expression. How does compiler know which overload of the std::forward function has to be called?
Because you're providing the template argument explicitly (you're providing the <T>); there's no type deduction.
In the call foo_as_always(i);, i is an lvalue so T is deduced to int &, and this is what you provide to std::forward.
In the call foo_as_always(0);, 0 is an rvalue and so T is deduced to int, and this is again what you provide to std::forward.
In both cases, it ends up calling the first overload, of course, since t is an lvalue, as you say. But the return type differs - in the first case, it's int& &&, so int&, in the second case, it's int &&.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With