C++ reinterpret_cast(或任何cast)能否将Xvalue转换为左值?
以下代码是否合法(根据C++11和/或C++14标准) 编辑 仅供参考,这是一个定制的演员阵容,它比以前的演员阵容毛茸茸的,在C++11上对GCC和Clang都有效,它将是以下C++ reinterpret_cast(或任何cast)能否将Xvalue转换为左值?,c++,c++11,language-lawyer,c++14,reinterpret-cast,C++,C++11,Language Lawyer,C++14,Reinterpret Cast,以下代码是否合法(根据C++11和/或C++14标准) 编辑 仅供参考,这是一个定制的演员阵容,它比以前的演员阵容毛茸茸的,在C++11上对GCC和Clang都有效,它将是以下lvalue函数: #include <iostream> namespace non_std { template <typename T> constexpr T &lvalue(T &&r) noexcept { return r; } } void
lvalue
函数:
#include <iostream>
namespace non_std {
template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }
}
void divs(int &a, int &b) {
int t = a;
a /= b;
b /= t;
}
int main() {
using namespace std;
using namespace non_std;
int i_care_for_this_one = 4;
divs(i_care_for_this_one, lvalue(2));
cout << i_care_for_this_one << endl;
}
#包括
名称空间非标准{
模板
constexpr T&lvalue(T&r)noexcept{return r;}
}
无效分区(内部和a、内部和b){
int t=a;
a/=b;
b/=t;
}
int main(){
使用名称空间std;
使用非标准名称空间;
int i_care_for_this_one=4;
divs(我关心这个,左值(2));
cout本标准的相关章节为5.2.10[expr.reinterpret.cast]。有两个相关段落:
首先,第1款以以下内容结尾:
不能使用reinterpret_cast显式执行其他转换
…和第11段,因为任何其他条款均不适用:
如果“指向T1
的指针”类型的表达式可以显式转换为“指向T2
的指针”类型,则类型为T1
的glvalue表达式可以转换为类型“引用T2
”使用reinterpret\u cast
。结果引用与源glvalue相同的对象,但具有指定的类型。[注意:即,对于左值,引用castreinterpret\u cast(x)
与使用内置&
和*
运算符的转换*reinterpret\u cast(&x)
具有相同的效果(同样,对于reinterpret_cast(x))
-结束说明]不创建临时文件,不制作副本,也不调用构造函数(12.1)或转换函数(12.3)
所有其他子句不适用于对象,仅适用于指针、函数指针等。由于右值不是glvalue,因此代码是非法的。更新:代码在C++11中格式不正确。下面的答案适用于C++14。请参阅此答案末尾的注释
我相信这段代码的格式和定义都很好
std::move
的结果是一个xvalue[1],它是glvalue的一种;标准的措辞似乎允许使用reinterpret_cast
将glvalue转换为左值引用:
如果表达式类型为“指针”,则类型为T1
的glvalue表达式可以强制转换为类型为“引用T2
”的表达式
toT1
“可以使用重新解释转换显式转换为类型“指向T2
”。结果引用
指向与源glvalue相同的对象,但具有指定的类型。[注意:即,对于左值,引用
castreinterpret\u cast(x)
与转换*reinterpret\u cast(&x)
具有相同的效果
内置的&
和*
运算符(同样适用于重新解释转换(x)
)。-结束说明]没有临时
创建,不进行复制,并且不调用构造函数(12.1)或转换函数(12.3)。73
由于“指向int
”的指针可以转换为“指向int
”,因此也允许此重新解释。该标准没有说明目标类型必须是左值引用还是右值引用
强制转换的结果由上面的段落很好地定义:它引用与源glvalue相同的对象,即值为5
的临时int
对象([dcl.init.ref]指定将prvalue绑定到引用时创建临时对象。)
通过int&
访问值也不会违反任何别名规则,因为原始对象也是int
类型。事实上,我相信通过由此获得的左值修改临时值甚至是定义良好的
注意:C++11的措辞是“左值表达式”,而不是“glvalue表达式”。带有“glvalue表达式”的措辞来自N3936,这是C++14的最终工作草案。我不是标准化过程的专家,但我相信这意味着“左值”到“glvalue”的变化已经被委员会投票通过,当ISO发布C++14标准时,它将非常类似于上面所说的
[1] 除非在极少数情况下,参数是一个函数;在这种情况下,结果是一个左值,因为没有函数右值。问题在于是否允许重新解释转换将xvalue转换为左值。与其他粘贴的内容相反,相关段落(5.2.10.11)只提到左值:
T1类型的左值表达式可以强制转换为“reference to”类型
T2“如果
“指向T1的指针”类型的表达式可以显式转换为
使用重新解释转换的“指向T2的指针”
Michael Wong提交了一份将措辞改为glvalue的提案,但似乎碰壁了:
我认为这意味着,到目前为止,转换是不合法的,因为它只明确允许从左值进行转换。为什么不尝试使用符合标准的编译器编译它&看看接下来会发生什么?您可能会提到在GCC上收到的错误消息。Visual Studio 2013说错误C2102:“&”需要l值e> @MattMcNabb参数是xvalue,因此是glvalue,最后一段说glvalue可以转换为引用。@Brian:“参数是xvalue”-如果您指的是5
,则不是真的…它是3.10/1中的prvalue“诸如12
、7.3e5
或true
等文本的值也是一个prvalue。”(请注意,prvalue不是glvalue)。@TonyD它在被move
d之后成为一个xvalue。正如Brian指出的,std::move
的结果是一个xvalue(这是一个glvalue);[basic.lval]
➤ g++-4.9 -std=c++1y sample.cpp -o sample
sample.cpp: In function 'int main()':
sample.cpp:11:40: error: invalid cast of an rvalue expression of type 'std::remove_reference<int>::type {aka int}' to type 'int&'
foo(reinterpret_cast<int &>(move(5)));
^
#include <iostream>
namespace non_std {
template <typename T>
constexpr T &lvalue(T &&r) noexcept { return r; }
}
void divs(int &a, int &b) {
int t = a;
a /= b;
b /= t;
}
int main() {
using namespace std;
using namespace non_std;
int i_care_for_this_one = 4;
divs(i_care_for_this_one, lvalue(2));
cout << i_care_for_this_one << endl;
}