I'm struggling to understand what exactly happens when passing a reference-to-function to a function as a universal reference (what type is being deduced). Let's suppose we have a function foo that takes a param as a universal reference:
template<typename T>
void foo(T&& param)
{
std::cout << __PRETTY_FUNCTION__ << std::endl;
}
And then let's do the following:
void(&f)(int) = someFunction;
foo(f);
The result will be:
void foo(T&&) [with T = void (&)int]
This is perfectly understandable: we are passing lvalue to our function foo, so the deduced type is void(&)int, and the type of the param will be "void(&& &)int" which under reference collapsing rules becomes void(&)int. Param will be just an lvalue reference to a function.
But when I do the following:
void(&f)(int) = someFunction;
foo(std::move(f));
foo will print:
void foo(T&&) [with T = void (&)int]
which is exactly the same as before! What is happening here? Why the result is the same as when passing lvalue? I would expect that since we are passing rvalue to foo, the deduced type should be T = void(int), and param should become void(&&)int. This always happen with all other "normal" types (like classes, primitive types, etc.) Why is it different when dealing with function references?
A
std::move
is a glorifiedstatic_cast
to rvalue reference type. The standard says that casting to an rvalue reference to function type still yields an lvalue. Per [expr.static.cast]/p1:Concerning the value category of the
std::move()
function call, which returns an rvalue reference designating the result of the conversion, we can also see from [expr.call]/p10 that a function call is an lvalue if its return type is an rvalue reference to function type: