Why is an expression expression for an rvalue expression for a function equal to an lvalue?

Here is cppreference-lvalue , I found that

The value of the Cast expression for rvalue for a function is lvalue.

I was curious, so I did 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 is an expression expression for an rvalue expression for a function equal to an lvalue? Is it because the type of function does not require moving semantics or something else? Or I misunderstand this word.

The value of the expression for the rvalue expression for the function is lvalue

+5
source share
2 answers

From the definition of categories of values ​​in C ++ 11 3.10 / 1 (emphasis):

  • The value lvalue (...) denotes a function or object ....

  • The value xvalue (value "eXpiring") also refers to the object, ...

  • Rvalue (...) is an xvalue, a temporary object (12.2), or its subobject or value that is not associated with the object.

  • The value of prvalue ("pure" rvalue) is the value of r, which is not the value of x ....

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

It is also reflected in 5.2.9 / 1:

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

As for the reason for this, of course, I can only speculate (not being part of the standardization committee). But I suppose that it would be pointless to have rvalues ​​of type of function - a function can never be temporary, it can never be at the end or at the end of its life.

+8
source

I am very grateful for the information ( N3055 , link to his comment) provided by TC to facilitate a quick overview of the answers, and I quote some paragraphs related to this problem. This answer tells us why

Rvalue references (e.g. traditional lvalue references) can be associated with a function. Handling the return value of a rvalue reference as an rvalue, however introduces a new concept of the rvalue function in the language. There was no such idea before - the lvalue function used in the context of the rvalue becomes the rvalue-pointer to the function, not the function rvalue - therefore the current draft of the standard does not describe how such rvalues ​​should be processed. In particular, function calls and conversions to function pointers are specified in terms of the lvalues ​​function , so the most likely use of rvalue references for functions is undefined in the current edition.

One possible solution to these problems would be to maintain the current approach to handling the rvalue return value as an rvalue, but to add various caveats to the rvalues ​​specification so that those coming from the rvalue reference will have special characteristics. This could be called a ridiculous rvalue approach. However, further study of the current wording of the draft standard indicates that the problems listed above are probably just the tip of the iceberg: many of the specifications that should be applied to objects for which rvalue links to links, such as the lifetime of an object, alias rules, etc. ., are stated in terms of lvalues, so that the rvalue cautions list can get for quite some time .

This suggests an alternative approach: returning a reference to rvalue values ​​should actually be considered as l values, with some exceptions to allow them to be considered as rvalues ​​in cases where it is intended, that is, in a reference binding, overload resolution and subtraction of the template argument. This idea, dubbed the "ridiculous lvalue" approach, is embodied in earlier versions of this article. After extensive discussions in the Main Working Group at a meeting in Pittsburgh (May 8–13, 2010) ......

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

To call a non-member function or a static member function, the postfix expression must be either an lvalue that refers to (in this case, the standard conversion of the function to a pointer (4.3) is suppressed in a postfix expression), or it must have a pointer to a type functions.

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

So static_cast<void(&&)(int)>(test)(555); in order.

0
source

Source: https://habr.com/ru/post/1215575/


All Articles