c++ - 用右值初始化左值引用

标签 c++ c++11 gcc clang

我用 gcc/clang 构建了这段代码并得到了不同的结果:

#include <iostream>
#include <sstream>

int main() {
    std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
}
  • 为什么 gcc 允许用右值初始化左值引用 (std::stringstream(""))?
  • 为什么 clang 会尝试调用复制构造函数?

海湾合作委员会4.9.1

没有错误

clang 3.4

prog.cc:5:63: error: call to implicitly-deleted copy constructor of 'istream' (aka 'basic_istream<char>')
    std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
                                                             ^~~~~~~~
/usr/local/libcxx-3.4/include/c++/v1/istream:185:5: note: copy constructor is implicitly deleted because 'basic_istream<char, std::__1::char_traits<char> >' has a user-declared move constructor
   basic_istream(basic_istream&& __rhs);
   ^
prog.cc:5:28: error: calling a protected constructor of class 'std::__1::basic_istream<char, std::__1::char_traits<char> >'
   std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
                          ^
/usr/local/libcxx-3.4/include/c++/v1/istream:185:5: note: declared protected here
   basic_istream(basic_istream&& __rhs);
   ^
prog.cc:5:28: error: calling a protected constructor of class 'std::__1::basic_istream<char, std::__1::char_traits<char> >'
   std::istream& is = 1 ? std::move(std::stringstream("")) : std::cin;
                          ^
/usr/local/libcxx-3.4/include/c++/v1/istream:185:5: note: declared protected here
   basic_istream(basic_istream&& __rhs);
   ^

最佳答案

GCC 的行为是一个错误,它是 been fixed on trunk .铛是正确的。这是一个困惑的情况,因为条件运算符的第二个和第三个操作数具有混合值类别:

  • std::move(std::stringstream(""))std::stringstream 类型的 xvalue*;
  • std::cinstd::istream 类型的左值。

相关标准报价(§5.16 [expr.cond]/p3-6)可以在this answer中找到.够长了,我真的不想复制过来。我将概述它是如何应用于此代码的:

  • 显然 std::istream 无法以任何方式转换以匹配 std::stringstream,无论值类别如何;
  • 鉴于引用必须直接绑定(bind)到左值 - 这里没有左值供引用绑定(bind);
  • std::istreamstd::stringstream 的基类,因此根据 p3 的第 3 个项目符号,std::stringstream 类型的 xvalue 可以并且将通过复制初始化转换为 std::istream 类型的临时纯右值,它替换原始操作数以供进一步分析。
  • 现在第二个操作数是 std::istream 类型的纯右值,第三个操作数是 std::istream 类型的左值,它们有不同的值类别所以p4 不适用。
  • 因此结果是每个 p5 的纯右值。由于它们具有相同的类型,因此不执行 p5 中指定的重载决策,您继续执行 p6。
  • p6中适用的项目符号是

    The second and third operands have the same type; the result is of that type. If the operands have class type, the result is a prvalue temporary of the result type, which is copy-initialized from either the second operand or the third operand depending on the value of the first operand.

    因此它从转换后的第一个操作数或第二个操作数 (std::cin) 复制初始化结果(临时纯右值)。

因此出现错误:

  • 从左值 (std::cin) 复制初始化右值 std::istream 结果将使用复制构造函数,并且无法复制流。<
  • std::stringstream 的第二个操作数复制初始化右值临时 std::istream xvalue 是一个移动,但是 std::istream 的移动构造函数受到保护。

* 有关术语(左值、xvalue、prvalue 等),请参阅 What are rvalues, lvalues, xvalues, glvalues, and prvalues?

关于c++ - 用右值初始化左值引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27879704/

相关文章:

c++ - 在 C++ 中将元素插入 2D Vector 的顺序

c++ - std::vector<Eigen::Vector3d> 到 Eigen::MatrixXd Eigen

c++ - 头文件中的 static const std::string

C++多线程: Visible side-effects of non-atomic variables

C++ 数组大小声明和常量

.net - 如何保护用 C++ .NET 编写的应用程序

c++ - Q : C++ - Reversing a string (sentence and word) using a class

c++ - 如何在 centos 6 上恢复系统 gcc 编译器

c - 如何开始使用 GCC/GNU

c - 宏扩展 : Argument with Commas