C++ reinterpret_cast(或任何cast)能否将Xvalue转换为左值?

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

以下代码是否合法(根据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 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相同的对象,但具有指定的类型。[注意:即,对于左值,引用cast
reinterpret\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
”的表达式 to
T1
“可以使用
重新解释转换显式转换为类型“指向
T2
”。结果引用 指向与源glvalue相同的对象,但具有指定的类型。[注意:即,对于左值,引用 cast
reinterpret\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;
}