Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How does std::forward receive the correct argument?

Consider:

void g(int&);
void g(int&&);

template<class T>
void f(T&& x)
{
    g(std::forward<T>(x));
}

int main()
{
    f(10);
}

Since the id-expression x is an lvalue, and std::forward has overloads for lvalues and rvalues, why doesn't the call bind to the overload of std::forward that takes an lvalue?

template<class T>
constexpr T&& forward(std::remove_reference_t<T>& t) noexcept;
like image 250
template boy Avatar asked Mar 19 '15 01:03

template boy


People also ask

How does std forward work?

The std::forward function as the std::move function aims at implementing move semantics in C++. The function takes a forwarding reference. According to the T template parameter, std::forward identifies whether an lvalue or an rvalue reference has been passed to it and returns a corresponding kind of reference.

What do std :: move and std :: forward do?

std::move takes an object and casts it as an rvalue reference, which indicates that resources can be "stolen" from this object. std::forward has a single use-case: to cast a templated function parameter of type forwarding reference ( T&& ) to the value category ( lvalue or rvalue ) the caller used to pass it.

What is perfect forwarding in C++?

What is Perfect Forwarding. Perfect forwarding allows a template function that accepts a set of arguments to forward these arguments to another function whilst retaining the lvalue or rvalue nature of the original function arguments.

What are Lvalues and Rvalues in C++?

Lvalues and rvalues are fundamental to C++ expressions. Put simply, an lvalue is an object reference and an rvalue is a value. The difference between lvalues and rvalues plays a role in the writing and understanding of expressions.


1 Answers

It does bind to the overload of std::forward taking an lvalue:

template <class T>
constexpr T&& forward(remove_reference_t<T>& t) noexcept;

It binds with T == int. This function is specified to return:

static_cast<T&&>(t)

Because the T in f deduced to int. So this overload casts the lvalue int to xvalue with:

static_cast<int&&>(t)

Thus calling the g(int&&) overload.

In summary, the lvalue overload of std::forward may cast its argument to either lvalue or rvalue, depending upon the type of T that it is called with.

The rvalue overload of std::forward can only cast to rvalue. If you try to call that overload and cast to lvalue, the program is ill-formed (a compile-time error is required).

So overload 1:

template <class T>
constexpr T&& forward(remove_reference_t<T>& t) noexcept;

catches lvalues.

Overload 2:

template <class T> constexpr T&& forward(remove_reference_t<T>&& t) noexcept;

catches rvalues (which is xvalues and prvalues).

Overload 1 can cast its lvalue argument to lvalue or xvalue (the latter which will be interpreted as an rvalue for overload resolution purposes).

Overload 2 can can cast its rvalue argument only to an xvalue (which will be interpreted as an rvalue for overload resolution purposes).

Overload 2 is for the case labeled "B. Should forward an rvalue as an rvalue" in N2951. In a nutshell this case enables:

std::forward<T>(u.get());

where you are unsure if u.get() returns an lvalue or rvalue, but either way if T is not an lvalue reference type, you want to move the returned value. But you don't use std::move because if T is an lvalue reference type, you don't want to move from the return.

I know this sounds a bit contrived. However N2951 went to significant trouble to set up motivating use cases for how std::forward should behave with all combinations of the explicitly supplied template parameter, and the implicitly supplied expression category of the ordinary parameter.

It isn't an easy read, but the rationale for each combination of template and ordinary parameters to std::forward is in N2951. At the time this was controversial on the committee, and not an easy sell.

The final form of std::forward is not exactly what N2951 proposed. However it does pass all six tests presented in N2951.

like image 99
Howard Hinnant Avatar answered Sep 27 '22 22:09

Howard Hinnant