Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does the compiler know that which overload of std::forward function has to be called?

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?

like image 844
Sadeq Avatar asked Aug 22 '14 10:08

Sadeq


1 Answers

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 &&.

like image 88
Angew is no longer proud of SO Avatar answered Oct 27 '22 00:10

Angew is no longer proud of SO