可以reinterpret_cast(或任何强制转换)将xvalues转换为左值吗?

pep*_*ico 8 c++ language-lawyer reinterpret-cast c++11 c++14

以下代码是否合法(通过C++ 11和/或C++ 14标准)?

#include <iostream>
#include <utility>

using namespace std;

void foo(int &a) {
    cout << a << endl;
}

int main() {
    foo(reinterpret_cast<int &>(move(5)));
}
Run Code Online (Sandbox Code Playgroud)
  • 如果是,是不确定的行为?
  • 如果它不是未定义的行为,我甚至可以afoo没有变成UB的情况下进行变异吗?

它在clang 3.5上编译,而不是在gcc 4.9上编译.GCC错误:

? 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)));
                                        ^
Run Code Online (Sandbox Code Playgroud)

编辑

仅供参考,一个定制的演员阵容,比以前更少毛茸茸,并且适用于GCC和Clang的C++ 11,它将具有以下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;
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*ian 6

更新:代码在C++ 11中格式不正确.以下答案适用于C++ 14.请参阅本答案末尾的注释.

我相信这段代码既有良好的形式,也有明确的定义.这就是原因.

结果std::move是xvalue [1],它是一种glvalue; 并且将glvalue转换为左值引用reinterpret_cast似乎是标准的措辞所允许的:

如果类型"指向" 的表达式可以使用a 显式转换为"指向" 的类型,则T1可以将类型的glvalue表达式强制转换为"引用T2"类型.结果引用与源glvalue相同的对象,但具有指定的类型.[注意:也就是说,对于左值,参考演员与使用内置和运算符的转换具有相同的效果(同样适用于). - 尾注]没有创建临时,没有复制,并且没有调用构造函数(12.1)或转换函数(12.3).73T1T2reinterpret_castreinterpret_cast<T&>(x)*reinterpret_cast<T*>(&x)&*reinterpret_cast<T&&>(x)

由于"指向"的指针int可以转换为"指向int",因此reinterpret_cast也允许这样做.该标准没有说明目标类型是否必须是左值引用或右值引用.

转换的结果由上面的段落明确定义:它引用与源glvalue相同的对象---即int具有值的临时对象5.([dcl.init.ref]指定在将prvalue绑定到引用时创建临时.)

通过它访问值int&也不违反任何别名规则,因为原始对象也是类型int.事实上,我相信甚至可以通过如此获得的左值来修改临时值.

注意: C++ 11的措辞是"左值表达式",而不是"glvalue表达式".带有"glvalue表达式"的措辞来自N3936,这是C++ 14的最终工作草案.我不是标准化过程如何工作的专家,但我相信这意味着"左值"到"glvalue"的变化已经被委员会投票,当ISO发布C++ 14标准时,它就会出现与上面说的很相似.

[1]除了极少数情况下,论证是一个函数; 在这种情况下,结果是左值,因为没有函数rvalues.


小智 5

问题在于是否允许reinterpret_cast将xvalues转换为lvalues.与其他人粘贴的内容相反,相关段落(5.2.10.11)仅提到左值:

如果可以使用reinterpret_cast将"指向T1的指针"类型的表达式显式转换为"指向T2的指针"类型,则可以将类型T1的左值表达式强制转换为"对T2的引用"类型.

迈克尔·黄提交了一份提案,要求将措辞改为glvalue,但它似乎已经碰壁了:

http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#1268

我认为这意味着,截至目前,转换不合法,因为它只明确允许从左值转换.