std::vector:无法将 'std::ostream {aka std::basic_ostream<char>}' lvalue 绑定到 'std::basic_ostream<char>&&'

std::vector : cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

提问人:thor 提问时间:7/7/2014 最后编辑:Communitythor 更新时间:7/7/2014 访问量:38969

问:

我在尝试做一些简单的事情时遇到了一个令人困惑的错误消息,比如

std::cout << std::vector<int>{1,2,3};

其中说

 cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'
 int main() {  std::cout << std::vector<int>{1,2,3}; }

(使用 gcc-4.8.1 和 -std=c++11 进行测试)

SO 也有类似的问题,例如重载运算符<<:无法将左值绑定到“std::basic_ostream<char>&&”,这是关于一些带有嵌套类的用户定义类。还有一个方法可以解决该问题的公认答案。

但我不知道这是否适用于.有人可以解释为什么这个错误会发生,以及如何解释它吗?std::vectorstd::vector

谢谢

C++ GCC C++11 STL IOstream

评论


答:

25赞 Angew is no longer proud of SO 7/7/2014 #1

与模板相关的错误消息有时会令人困惑。问题在于标准库没有定义用于插入(或任何其他容器,就此而言)到 .因此,编译器无法找到合适的重载,并尽可能地报告此故障(不幸的是,在您的情况下,这不太好/可读)。operator <<std::vectorstd::ostreamoperator <<

如果要流式传输整个容器,可以使用 std::ostream_iterator

auto v = std::vector<int>{1, 2, 3};
std::copy(begin(v), end(v), std::ostream_iterator<int>(std::cout, " "));

至于为什么你会得到这个神秘的错误,分析完整的错误消息会有所帮助:

prog.cpp: In function ‘int main()’:
prog.cpp:13:37: error: cannot bind ‘std::ostream {aka std::basic_ostream<char>}’ lvalue to ‘std::basic_ostream<char>&&’
  std::cout << std::vector<int>{1,2,3};
                                     ^
In file included from /usr/include/c++/4.8/iostream:39:0,
                 from prog.cpp:3:
/usr/include/c++/4.8/ostream:602:5: error:   initializing argument 1 of ‘std::basic_ostream<_CharT, _Traits>& std::operator<<(std::basic_ostream<_CharT, _Traits>&&, const _Tp&) [with _CharT = char; _Traits = std::char_traits<char>; _Tp = std::vector<int>]’
     operator<<(basic_ostream<_CharT, _Traits>&& __os, const _Tp& __x)
     ^

显然有一个模板重载,它采用类型的 lhs 参数和模板化的 rhs 参数;它的存在是为了允许插入到临时流中。由于它是一个模板,因此它将成为代码中表达式的最佳匹配项。但是,是一个左值,因此它不能绑定到 。因此错误。operator<<std::ostream&&std::coutstd::ostream&&

评论

0赞 thor 7/7/2014
感谢您的回答,它解释了问题的第一部分。我也滚动自己的代码来打印矢量。我不明白的(问题的第二部分)是当找不到重载时,我们如何获得这种类型的 l-ref/r-ref 错误。
0赞 David Rodríguez - dribeas 7/7/2014
该重载不是实现细节,而是标准 27.7.1 <ostream> 概要所要求的,以允许插入到临时流中。像这样:std::ofstream("output.txt") << "Hi there\n";
0赞 Angew is no longer proud of SO 7/7/2014
@DavidRodríguez-dribeas 谢谢,修改了。我只是快速检查了 cpreference,没有在那里找到它。
-1赞 Vlad from Moscow 7/7/2014 #2

类中没有为 类 定义。operator <<std::vectorstd::basic_ostream

你想要的是以下内容

for ( int x  : std::vector<int> { 1, 2, 3 } ) std::cout << x << ' ';
std::cout <<  std::endl;

虽然它可以写得更简单

for ( int x  : { 1, 2, 3 } ) std::cout << x << ' ';
std::cout <<  std::endl;
9赞 Ali 7/7/2014 #3

这是 gcc 的一个已知问题,我就此提交了增强请求。

“唯一”的问题是您尝试打印到控制台的内容没有.不幸的是,错误消息不是很有帮助。:(operator<<

顺便说一句,这个问题与 l 值和 r 值引用无关。一个最小的例子:vector

#include <iostream>

struct A { };

int main() {
    A a;
    std::cout << a;
}

有关血腥的细节,请参阅增强请求中的讨论。简而言之,gcc 开发人员已经尝试改进错误消息,但事实证明这是出了名的困难。

其价值而言,在我看来,clang 带有 libc++ 的错误消息更清晰:

clang++ -std=c++11 -stdlib=libc++ -lc++abi main.cpp && ./a.out
main.cpp:7:15: error: invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'A')
    std::cout << a;
    ~~~~~~~~~ ^  ~

在这里,第一行清楚地说明了问题所在。

评论

0赞 David Rodríguez - dribeas 7/7/2014
虽然编译器的输出可能更好,但报告的错误在标准的上下文中是有道理的。它无法编译,并且除了参数的左值之外,存在几乎匹配的重载......我认为该错误更像是增强请求,而不是真正的错误
1赞 Ali 7/7/2014
@DavidRodríguez-dribeas 我修改了我的答案并将“错误报告”更改为“增强请求”。那是唯一一个说“错误”的地方。对我来说,快速识别问题非常重要。当我第一次遇到这个问题时,我花了一些时间弄清楚发生了什么;错误消息使我走上了错误的轨道。正如这个问题所表明的,我不是唯一一个难以理解该错误消息的人。好吧,将此问题称为增强请求或任何您想要的问题,即使是 gcc 开发人员也承认这是一个问题并试图改进它。所以这是一个问题
0赞 Ali 7/7/2014
@DavidRodríguez-dribeas 好吧,我已经修改了几个地方的措辞,也许它太强烈了。我希望你现在能发现它没问题,谢谢你提请我注意它。
0赞 David Rodríguez - dribeas 7/8/2014
不要误会我的意思,如果 gcc 开发人员认为这是一个错误,我会理解(并赞赏)。我只是想提请大家注意,这是一个 QoI 问题,而不是编译器处理程序的错误。
0赞 Ali 7/8/2014
@DavidRodríguez-dribeas同意了。这就是我修改答案的原因。感谢您提请我注意我有问题的措辞!