C++ 为什么将表达式强制转换为对函数的右值引用是左值?

C++ 为什么将表达式强制转换为对函数的右值引用是左值?,c++,c++11,C++,C++11,在这里,我发现 对函数的右值引用的强制转换表达式是左值 我很好奇,所以我做了以下实验: #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){

在这里,我发现

对函数的右值引用的强制转换表达式是左值

我很好奇,所以我做了以下实验:

#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;
}
#包括
使用名称空间std;
类型定义无效(&&funr)(内部);
类型定义无效(&funl)(内部);
无效测试(整数){

cout根据C++11 3.10/1(重点矿山)中的值类别定义:

  • 左值(…)表示函数或对象

  • xvalue(“到期”值)也指对象

  • 右值(…)是xvalue、临时对象(12.2)或其子对象,或与对象无关的值

  • prvalue(“纯”右值)是不是xvalue的右值

请注意,只有左值类别可以是函数,其他所有类别只能是值或对象

这也在5.2.9/1中得到了回应:

表达式
static_cast(v)
的结果是将表达式
v
转换为类型
T
If
T
是左值引用类型还是函数类型的右值引用,结果是左值;如果
T
是右值 引用对象类型,结果为xvalue;否则,结果为prvalue


至于原因,我当然只能猜测(不是标准化委员会的成员)。但我的猜测是,使用函数类型的右值是没有意义的——函数永远不会是临时的,它永远不会在或接近其生命周期的末尾。

非常感谢您提供的信息(N3055,在他的评论中链接),以便于快速概述答案,我引用了一些与此问题相关的段落。此答案告诉我们原因

右值引用(像传统的左值引用)可以绑定到 函数。将右值引用返回值视为右值, 但是,在 语言。以前没有这样的想法–使用了函数左值 在右值上下文中,成为指向函数右值的指针,而不是 函数rvalue–因此当前的标准草案没有描述如何 这类右值需要处理。尤其是函数调用和 函数指针的转换是根据函数来指定的 左值,因此对函数的右值引用最合理的用法是 当前措辞中未定义。

这些问题的一个可能解决方案 问题是要维持目前治疗癌症的方法 右值引用返回值作为右值,但添加了各种警告 对于右值的规范,使那些来自右值的 引用将具有特殊的特征。这可以称为 “有趣的右值”方法。但是,进一步检查 标准草案的当前措辞表明,这些问题 上面列出的可能只是冰山一角:许多 应应用于右值所指向的对象的规范 引用(例如对象生存期、别名规则等)是 用左值来表达,因此右值警告列表可以 相当长

这表明了另一种方法:右值引用返回 值实际上应该被视为左值,只有少数例外 允许将它们作为右值处理,如果 预期的,即引用绑定、重载解析和 模板参数演绎。这个想法被称为“有趣的左值” 方法体现在本文的早期版本中。在匹兹堡(2010年3月8日至13日)会议的核心工作组中进行了广泛讨论后,

此外,正如5.2.2函数调用[expr.call]所述:

对于非成员函数或静态成员函数的调用, 后缀表达式应为表示 函数(在这种情况下,函数到指针的标准转换 (4.3)在后缀表达式上被抑制),或者 指向函数类型的指针

现在,
static\u cast(test)
是一个左值


所以
static_cast(test)(555);
是可以的。

我想技术上的答案是因为标准在[conv]/6、[expr.static.cast]/1等中这样说。一个很好的理由是(在评论中有额外的澄清)在中有一些讨论。