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