What is an rvalue reference to function type?
Asked Answered
K

2

17

I have recently wrapped my mind around the C++0x's concepts of glvalues, xvalues and prvalues, as well as the rvalue references. However, there's one thing which still eludes me:

What is "an rvalue reference to function type"? It is literally mentioned many times in the drafts. Why was such a concept introduced? What are the uses for it?

Ketch answered 10/8, 2011 at 19:42 Comment(1)
did you finally understand the answer? I have left a comment under the answer so if you are aware of the clarification please do provide it. thanksInevitable
H
19

I hate to be circular, but an rvalue reference to function type is an rvalue reference to function type. There is such a thing as a function type, e.g. void (). And you can form an rvalue reference to it.

In terms of the classification system introduced by N3055, it is an xvalue.

Its uses are rare and obscure, but it is not useless. Consider for example:

void f() {}
...
auto x = std::ref(f);

x has type:

std::reference_wrapper<void ()>

And if you look at the synopsis for reference_wrapper it includes:

reference_wrapper(T&) noexcept;
reference_wrapper(T&&) = delete; // do not bind to temporary objects

In this example T is the function type void (). And so the second declaration forms an rvalue reference to function type for the purpose of ensuring that reference_wrapper can't be constructed with an rvalue argument. Not even if T is const.

If it were not legal to form an rvalue reference to function, then this protection would result in a compile time error even if we did not pass an rvalue T to the constructor.

Haematozoon answered 10/8, 2011 at 20:31 Comment(9)
I think you meant void(). void()() was an erroneous demangling of GCC/binutils but was fixed some time ago.Cryosurgery
@Johannes: Thanks! That was most helpful!Haematozoon
This is creepy and I have problems understanding. About the last sentence about compile time error- wouldn't SFINAE just cause the second declaration to be ignored in this case?Ketch
@Kos: That's a good question and I'm afraid I don't have a good answer. The SFINAE rules were generalized late in the standardization process, and independently of this issue. And I don't know if they would have caught rvalue reference to function (if such a type were not valid), and SFINAE'd or error'd on it, and I don't have a way to test what would have happened. What you propose sounds like another valid design path the language could have chosen but didn't.Haematozoon
I see. And is this feature also related to lambdas somehow?Ketch
@Kos: Not that I know of. However I'm still learning lambdas myself, so don't take my word for it.Haematozoon
@HowardHinnant could you please clarify the last two paragraphs? I'm really having difficulty understanding that. basically reference_wrapper(T&); will be picked for the function right? since here f is an lvalue? am I right? what you are saying is that since both declarations can be valid for a function and that the second decl is deleted the first one will be selected? sorry for bothering you. thanks in advance and please helpInevitable
@HowardHinnant "rvalue reference to function type" means this void(&&)(), in this example?Inevitable
@Koushik: The deleted overload is needed for other cases, not this one. For example if T instantiates to some struct X, the deleted overload keeps the client from accidentally passing an rvalue X to reference_wrapper. In the case where a function is passed, both overloads are instantiated, and then overload resolution will choose the non-deleted one because functions are lvalues, not because the second one is deleted. But it is important that the compiler not declare an error prior to doing the overload resolution.Haematozoon
G
0

In the old c++ standard the following is forbidden:

int foo();
void bar(int& value);

int main()
{
    bar(foo());
}

because the return type of foo() is an rvalue and is passed by reference to bar().

This was allowed though with Microsoft extensions enabled in visual c++ since (i think) 2005.

Possible workarounds without c++0x (or msvc) would be declaring

void bar(const int& value); 

or using a temp-variable, storing the return-value of foo() and passing the variable (as reference) to bar():

int main()
{
    int temp = foo();
    bar(temp);
}
Gwinn answered 10/8, 2011 at 20:3 Comment(1)
Maybe I misunderstood the question, but I think the OP is talking about rvalues reference to function types (ie. lambdas and so on).Tintinnabulum

© 2022 - 2024 — McMap. All rights reserved.