Question

Can anyone please explain why this compiles and why does t end up with type int&?

#include <utility>

void f(int& r)
{
    ++r;
}

template <typename Fun, typename T>
void g(Fun fun, T&& t) 
{ 
    fun(std::forward<T>(t)); 
}

int main()
{
    int i = 0;

    g(f, i);
}

I see this on GCC 4.5.0 20100604 and GDB 7.2-60.2

Was it helpful?

Solution

Because of perfect forwarding, when the argument to P&& is an lvalue, then P will be deduced to the argument's type plus having a & attached. So you get int & && with P being int&. If the argument is an rvalue then P will be deduced to only the argument's type, so you would get an int&& argument with P being int if you would pass, for example 0 directly.

int& && will collapse to int& (this is a semantic view - syntactically int& && is illegal. But saying U && when U is a template parameter or a typedef refering to a type int&, then U&& is still the type int& - i.e the two references "collapse" to one lvalue reference). That's why t has type int&.

OTHER TIPS

If for some reason you really want to bind to lvalues or rvalues specifically, use metaprogramming:

#include <type_traits>

template <typename T>
typename std::enable_if<std::is_lvalue_reference<T&&>::value, void>::type
fun(T&& x)
{
    std::cout << "lvalue argument\n";
}

template <typename T>
typename std::enable_if<std::is_rvalue_reference<T&&>::value, void>::type
fun(T&& x)
{
    std::cout << "rvalue argument\n";
}

int main()
{
    int i = 42;
    fun(i);
    fun(42);
}
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top