【问题标题】:std::vector : cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'std::vector : 无法将 'std::ostream {aka std::basic_ostream<char>}' 左值绑定到 'std::basic_ostream<char>&&'
【发布时间】:2014-08-27 21:29:34
【问题描述】:

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

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 也有类似的问题,例如Overloading operator<<: cannot bind lvalue to ‘std::basic_ostream<char>&&’,这是关于一些用户定义的具有嵌套类的类。对于该问题的公认答案,还有一项工作。

但我不知道这是否适用于std::vector。谁能解释为什么std::vector会出现这个错误,以及如何解释它?

谢谢

【问题讨论】:

    标签: c++ gcc c++11 stl iostream


    【解决方案1】:

    与模板相关的错误消息有时会令人困惑。问题是标准库没有定义operator &lt;&lt; 的重载以将std::vector(或任何其他容器,就此而言)插入std::ostream。因此,编译器无法为 operator &lt;&lt; 找到合适的重载,并尽其所能报告此失败(不幸的是,在您的情况下这不太好/可读)。

    如果你想流式传输整个容器,你可以使用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)
         ^
    

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

    【讨论】:

    • 感谢您的回答,它解释了问题的第一部分。我也推出了自己的代码来打印矢量。我不明白(问题的第二部分)是当找不到重载时我们如何得到这种类型的 l-ref/r-ref 错误。
    • 该重载不是实现细节,但标准 27.7.1 概要要求允许插入到临时流中。比如:std::ofstream("output.txt") &lt;&lt; "Hi there\n";
    • @DavidRodríguez-dribeas 谢谢,已修改。我只是快速检查了 cppreference 并没有在那里找到它。
    【解决方案2】:

    这是 gcc 的一个已知问题,I filed an enhancement request regarding this.

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

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

    #include <iostream>
    
    struct A { };
    
    int main() {
        A a;
        std::cout << a;
    }
    

    有关详细信息,请参阅增强请求中的讨论。简而言之,gcc 开发人员已经尝试改进错误消息,但事实证明这非常困难。

    对于它的价值,clang's error message 与 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;
        ~~~~~~~~~ ^  ~
    

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

    【讨论】:

    • 虽然编译器的输出可能更好,但报告的错误在标准的上下文中是有意义的。它无法编译,并且存在 almost 匹配的重载,除了参数的左值性...我看到 bug 更像是增强请求而不是真正的错误。
    • @DavidRodríguez-dribeas 我修改了答案并将“错误报告”更改为“增强请求”。那是唯一一个说“虫子”的地方。快速识别问题对我来说非常重要。当我第一次遇到这个问题时,我花了一些时间弄清楚发生了什么。错误消息使我走错了路。正如这个问题所示,我不是唯一一个难以理解该错误消息的人。好吧,将此问题称为增强请求或任何您想要的,甚至 gcc 开发人员也承认这是一个问题并试图改进它。所以这一个问题。
    • @DavidRodríguez-dribeas 好的,我已经在几个地方修改了措辞,也许它太强了。我希望你现在会发现它没问题,谢谢你引起我的注意。
    • 不要误会我的意思,如果 gcc 开发人员认为这是一个错误,我会理解(并感激)。我只是想提请注意,这是一个 QoI 问题,而不是编译器处理程序的错误。
    • @DavidRodríguez-dribeas 同意。这就是我修改答案的原因。感谢您提请我注意我有问题的措辞!
    【解决方案3】:

    在类std::basic_ostream 中没有为类std::vector 定义operator &lt;&lt;

    你想要的是以下

    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;
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2018-03-03
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-09-28
      • 2014-05-24
      相关资源
      最近更新 更多