强制转换的结果是右值吗?
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】:
应该是一个 rvalue 但 webcompiler 正在运行 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*)&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。
【讨论】:
关键是对于从T
到T
的转换没有规则例外。以上是关于强制转换的结果是右值吗?的主要内容,如果未能解决你的问题,请参考以下文章