c++ - 为什么我可以 std::move 流右值引用到左值引用?

标签 c++ c++11 iostream move-semantics rvalue-reference

据我了解 C++11 引用,我不应该能够将右值引用绑定(bind)到(非常量)左值引用,因为前者可能绑定(bind)到临时对象,而后者绝不能绑定(bind)到一个临时的。

但是我发现这种奇怪的行为与临时流对象有关(我尽可能地减少了)

struct Dummy {};
template <typename Stream>
Stream& operator<<(Stream& s, Dummy) {
  return s << ".";          // <- (A)
}

template <typename Stream>
void pass(Stream&& s) {
  std::move(s) << Dummy();  // <- (X)   rvalue->lvalue conversion?
}

#include <fstream>
int main() {
  pass(std::fstream("test",std::ios::out));
}

如果我写 s << Dummy()在线 (X) , C++ 在 (A) 行提示, 说

error: invalid initialization of reference of type ‘std::basic_fstream<char>&’ from expression of type ‘std::basic_ostream<char>’

但是,为什么代码(如上所示)编译并按预期工作std::move 返回的右值引用应该像表达式 s 一样无法绑定(bind)到左值引用是,但两者都是gcc 4.6.1gcc 4.7.2 react 相同。

为什么这种现象似乎只适用于流?直接传递 Dummy&& 时到一个需要 T& 的函数使用和不使用 std::move 均失败.

最佳答案

basic_ostream过载 operator<<看起来像这样:

template <typename Elem, typename Traits, typename T>
basic_ostream<Elem, Traits>&
    operator<<(basic_ostream<Elem, Traits>&& sink, const T& val)
{
    return sink << val;
}

这在标准中称为“右值流插入”,位于 §27.7.3.9 [ostream.rvalue]。

它允许从右值 basic_ostream 隐式转换(某种)到一个左值。它是专门为允许 temporary streams to be usable without resorting to tricks 引入的.


至于省略move为什么会编译失败:

Stream& operator<<(Stream& s, Dummy)被称为没有 move ,Stream将是 std::fstream继承自 std::ostream (即 basic_ostream<char> )。

它将使用 basic_ostream<E, T>& operator<<(basic_ostream<E, T>&, const char*)重载以插入您的字符串,然后尝试返回该表达式的结果 ,这将是 ostream 。您不能从 std::ostream& 隐式向下转换至 std::fstream& , 所以你会得到一个错误。

您可以通过返回 s 来解决这个问题在它自己的行上(它不会被隐式地向上转换。)

move 不是问题,因为您通过了我们刚刚首先发现的右值到左值插入运算符。在该函数内部,流是一个 basic_ostream所以Stream也是如此,并且返回类型将匹配。

关于c++ - 为什么我可以 std::move 流右值引用到左值引用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14866360/

相关文章:

c++ - 在 C++11 别名模板上调用构造函数和运算符

c++ - 可变参数聚合作为核心语言功能

c++ - 分配新堆栈时的编程错误

c++ - 为什么调用没有主体的纯虚方法不会导致链接器错误?

c++ - ISO C++禁止在结构内初始化成员

c++ - fstream、ofstream、ostream、iostream 之间的区别

c++ - 标准流适配器

c++ - 了解 cout.operator<<() 的行为

c++ - 返回 C++ 堆栈变量

c++ - main.obj : error LNK2019: unresolved external symbol in C++ [duplicate]