Ron Tang
Ron Tang

Reputation: 1622

Why cast expression to rvalue reference to function is lvalue?

At here,cppreference-lvalue,I found that

Cast expression to rvalue reference to function is lvalue.

I was curious, so I carried out the following experiment:

#include <iostream>

using namespace std;


typedef void (&&funr) (int);
typedef void (&funl) (int);

void test(int num){
    cout<<num<<endl;//output:20
}

void foo(funr fun){
    fun(10);
}

void foo(funl fun){
    fun(20);//call this
}

template <typename T> void foo(T&& fun){
    cout<<is_same<T,void(&)(int)>::value<<endl;//true, it is lvalue. 
    cout<<is_same<T,void(int)>::value<<endl;//false, it isn't rvalue.
}
int main()
{

   foo(static_cast<void(&&)(int)>(test));
   return 0;
}

the fact that so.

Why cast expression to rvalue reference to function is lvalue? Is it because a function type is no need to move semantics or something else? Or I understand this word wrong.

Cast expression to rvalue reference to function is lvalue

Upvotes: 6

Views: 1090

Answers (2)

Ron Tang
Ron Tang

Reputation: 1622

Very grateful to the information(N3055,link at his comment) provided by T.C. , in order to facilitate a quick overview of the answers, and I quote some paragraphs related to this issue.This answer tells us why

rvalue references (like traditional lvalue references) can be bound to functions. Treating an rvalue reference return value as an rvalue, however, introduces the novel concept of a function rvalue into the language. There was previously no such idea – a function lvalue used in an rvalue context becomes a pointer-to-function rvalue, not a function rvalue – so the current draft Standard does not describe how such rvalues are to be treated. In particular, function calls and conversions to function pointers are specified in terms of function lvalues, so most plausible uses of rvalue references to functions are undefined in the current wording.

One possible resolution for these problems would be to maintain the current approach of treating an rvalue reference return value as an rvalue but to add various caveats to the specification of rvalues so that those coming from rvalue references would have special characteristics. This could be called the “funny rvalue” approach. However, further examination of the current wording of the draft Standard indicates that the problems listed above are probably only the tip of the iceberg: many of the specifications that should apply to the objects to which rvalue references refer, such as object lifetime, aliasing rules, etc., are phrased in terms of lvalues, so the list of rvalue caveats could get quite long.

This suggests an alternative approach: that rvalue reference return values should actually be seen as lvalues, with a few exceptions to allow them to be treated as rvalues in the cases where that is intended, i.e., in reference binding, overload resolution, and template argument deduction. This idea, dubbed the “funny lvalue” approach, is embodied in earlier versions of this paper.After extensive discussions in the Core Working Group at the Pittsburgh (March 8-13, 2010) meeting, ......

In addition,As 5.2.2 Function call[expr.call] says:

For a call to a non-member function or to a static member function, the postfix expression shall be either an lvalue that refers to a function (in which case the function-to-pointer standard conversion (4.3) is suppressed on the postfix expression), or it shall have pointer to function type.

Now static_cast<void(&&)(int)>(test) is an lvalue.

So static_cast<void(&&)(int)>(test)(555); is OK.

Upvotes: 1

It follows from the definition of value categories in C++11 3.10/1 (emphasis mine):

  • An lvalue (...) designates a function or an object. ...

  • An xvalue (an “eXpiring” value) also refers to an object, ...

  • An rvalue (...) is an xvalue, a temporary object (12.2) or subobject thereof, or a value that is not associated with an object.

  • A prvalue (“pure” rvalue) is an rvalue that is not an xvalue. ...

Notice that only the lvalue category can be a function, all the others are values or objects only.

It's also echoed in 5.2.9/1:

The result of the expression static_cast<T>(v) is the result of converting the expression v to type T. If T is an lvalue reference type or an rvalue reference to function type, the result is an lvalue; if T is an rvalue reference to object type, the result is an xvalue; otherwise, the result is a prvalue. ...

As for the why of it, I can of course only guess (not being part of the standardisation committee). But my guess is that it would make no sense to have rvalues of function type—a function can never be a temporary, it can never be at or near the end of its lifetime.

Upvotes: 9

Related Questions