强制转换的结果是右值吗?

Posted

技术标签:

【中文标题】强制转换的结果是右值吗?【英文标题】:Is the result of a cast an rvalue? 【发布时间】:2014-10-22 13:29:21 【问题描述】:

int a = 0;

那么(int)a 是标准 C++ 中的 右值 吗?

不同的编译器对此代码显示不同的结果:

#include <iostream>
using namespace std;

void f(int& x)

    cout << "l value" << endl;


void f(int&& x)

    cout << "r value" << endl;


int main()

    int a = 0;
    f((int)a);

不同结果的编译器:

1) http://cpp.sh/2r6

2) http://webcompiler.cloudapp.net/

【问题讨论】:

有人检查过是否存在connect 错误吗?粗略的搜索没有找到一个。 @Mgetz 我正在寻找,但我没有发现任何明显的东西。 Filed as a defect on connect 使用@ShafikYaghmour 的测试用例针对VS2013 允许临时对象绑定到非常量引用是 MSVC 长期存在的“功能”。使用/Za 选项将其关闭。 MS 终于回复了,这显然是由/Zc:rvalueCast (Enforce type conversion rules) 控制的,他们已将我的错误标记为已修复。我仍在寻求澄清将来是否会默认启用此功能。 【参考方案1】:

应该是一个 rvaluewebcompiler 正在运行 Visual Studio 并且 Visual Studio 有一个 extension which allows temporary objects to be bound to non-const lvalue references。 a bug/extension that casues it to generate an lvalue in this case 正如 Igor 指出的那样可以使用/Za (see it live) 禁用以上内容。

我们可以从草案 C++ 标准部分5.4 中看到它应该是一个右值特别是纯右值显式类型转换(强制转换表示法) 段落 1 说(强调我的):

表达式 (T) cast-expression 的结果是 T 类型。 如果 T 是左值引用类型或右值,则结果是左值 如果 T 是右值引用,则引用函数类型和 xvalue 对象类型; 否则结果是纯右值。[注意:如果 T 是 cv 限定的非类类型,忽略 cv 限定符 在确定结果纯右值的类型时;见 3.10。 -结尾 注意]

gcc 和 clang 的结果都是 rvalue,这是预期的结果。

顺便说一句,我建议在 webcompiler 上使用 rextester,因为 rextester 允许您共享您的程序并且还具有实时共享功能。

更新

Ben Voigt 指出了这个 bug report,因此 Visual Studio 似乎实际上产生了一个 lvalue。所以这不仅仅是extension which allows temporary objects to be bound to non-const lvalue references的情况。

正如 dyp 指出的那样,gcc used to have a cast to lvalue extension 也是如此。

更新 2

Mgetz 提交了bug report,回复是使用/Zc:rvalueCast flag 解决了这个问题,flag 的描述如下:

当指定 /Zc:rvalueCast 选项时,编译器正确 将右值引用类型标识为强制转换操作的结果 符合 C++11 标准。 When the option is not 指定时,编译器行为与 Visual Studio 2012 中的相同。 默认情况下,/Zc:rvalueCast 是关闭的。为了一致性和消除 使用强制转换的错误,我们建议您使用 /Zc:rvalueCast。

不清楚未来版本是否会默认启用此标志。

【讨论】:

+1 为您推荐。实时分享链接的有效期是多久? @MinimusHeximus 不确定,我只使用了很短的时间,网站没有记录它。 这个答案实际上是错误的。 Visual C++ 没有使用将左值引用绑定到临时对象的错误功能……它完全无法创建临时对象。请参阅马特的回答和我的错误报告 connect.microsoft.com/VisualStudio/Feedback/Details/615622 将右值绑定到左值引用的语言扩展仅在存在 对象时才有效;对于基本类型rextester.com/TOJWJL48414 的纯右值而言,情况并非如此。奇怪的是,gcc 曾经有一个类似的“扩展”,它允许将强制转换的结果用作左值:gcc.gnu.org/gcc-3.4/changes.html (cast-as-lvalue) 我只能假设(char) i = 5;*((char*)&amp;i) = 5;(用C 语言)写起来更方便。您可以在搜索“cast-as-lvalue”时找到一些讨论。例如。它似乎在早期的 C89 草案中。【参考方案2】:

在标准 C++ 中,int(a)(int)a 是右值(其他答案提供标准参考)。

您的代码示例正在利用 MSVC 中的错误/扩展,但并非乍一看。正如我们可以从这段代码中看到的,它在 MSVC 中工作:

#include <iostream>

int main()

    int x = 0;
    (int)x = 1;
    std::cout << x << std::endl;

MSVC 将(int)x 视为左值。

尽管 MSVC 有一个扩展允许右值绑定到非常量引用;该扩展仍然使右值引用比右值的左值引用更匹配。

【讨论】:

四年前我在 Connect 上报告了这个和其他几个变体:connect.microsoft.com/VisualStudio/Feedback/Details/615622【参考方案3】:

是的,转换为对象类型的结果是 rvalue,如 C++11 5.4/1 所指定:

如果T 是左值引用,则结果是左值 类型或对函数类型的右值引用,如果 T 是对对象类型的右值引用,则为 xvalue; 否则结果是prvalue

【讨论】:

关键是对于从TT 的转换没有规则例外。

以上是关于强制转换的结果是右值吗?的主要内容,如果未能解决你的问题,请参考以下文章

从函数返回的左值引用实际上是右值吗(从调用者的角度来看)?

C++11 move()函数:将左值强制转换为右值

C++11新特性:21—— C++11 move()函数:将左值强制转换为右值

C++ 中的类型转换和指针类型转换

golang os清空返回值

SV强制类型转换和常数