【问题标题】:ostream_iterator for a vector<int> does not compile. Why?vector<int> 的 ostream_iterator 无法编译。为什么?
【发布时间】:2021-04-08 21:15:57
【问题描述】:

请参阅以下最小可重现示例:

#include <iostream>
#include <vector>
#include <algorithm>

// Define inserter operator for std::vector<int>
std::ostream& operator << (std::ostream& os, const std::vector<int>& v) {
    std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
    return os;
}
// Define inserter operator for std::vector<std::vector<int>>
std::ostream& operator << (std::ostream& os, const std::vector<std::vector<int>>& vv) {
    
    // ******* Error in this line *****
    std::copy(vv.begin(), vv.end(), std::ostream_iterator<std::vector<int>>(os,"\n"));

    // OK. The following works and will call the operator above
    for (const std::vector<int>& v : vv) os << v << '\n';
    return os;
}
int main() {
    std::vector<std::vector<int>> vvi{ {1,2}, {3,4,5}, {6,7,8,9 } };
    std::cout << vvi;
    return 0;
}

std::ostream_iterator&lt;std::vector&lt;int&gt;&gt; 不会编译,编译器说:

二进制 '

虽然std::vector&lt;int&gt; 的插入运算符可用。

如果我改为使用:

for (const std::vector<int>& v : vv) os << v << '\n';

std::vector&lt;int&gt; 的插入运算符将被调用。但不是std::ostream_iterator

CppReference 对我没有帮助。

为什么不编译?

【问题讨论】:

    标签: c++ vector iterator ostream


    【解决方案1】:

    第一个问题是你错过了一个

    #include <iterator>
    

    您表示您已经熟悉 cppreference.com,因此您应该注意 std::ostream_iterator 被注明需要此头文件。

    但编译失败的真正原因是std::copy 调用了重载运算符,它自然位于std 命名空间中。由于调用&lt;&lt; 运算符的代码位于std 命名空间中,因此重载解析在std 命名空间中搜索&lt;&lt; 的已定义重载,并为各种本机类型找到一大堆。所有这些重载决议都失败了。它们都不适合std::vector&lt;int&gt;搜索全局命名空间,以查找您的自定义 &lt;&lt; 重载,因为在 std 命名空间中至少找到一个 &lt;&lt; 重载。游戏结束。

    如果std 命名空间中没有定义&lt;&lt; 重载,则重载解析最终会找到您的自定义重载。唉,事实并非如此。

    消除编译错误的一种方法是将重载放入std 命名空间:

    namespace std {
        // Define inserter operator for std::vector<int>
        std::ostream& operator << (std::ostream& os, const std::vector<int>& v) {
            std::copy(v.begin(), v.end(), std::ostream_iterator<int>(os, " "));
            return os;
        }
    }
    

    但是,this is pedantic undefined behavior。无论如何,这就是编译错误的原因:首先在std 命名空间中搜索&lt;&lt; 的现有重载,因为它们是从std::copy 中调用的,并且首先找到现有的重载解决方案,所以不考虑其他命名空间中的其他潜在重载。

    【讨论】:

    • 很好且易于理解的解释。我仍然不满意我的问题显然没有合规的解决方案。所以,我会将插入器包装在一个类中,或者为提取器创建一个代理。无论如何,+1+接受
    • 你的意思是不是因为operator&lt;&lt;是由std::ostream_iterator调用的,而不是std::copy()本身? std::copy() 没有 operator&lt;&lt; 的概念,因为它只是将值从一个迭代器复制到另一个迭代器。调用operator&lt;&lt;的是std::ostream_iterator
    • @RemyLebeau:你是对的。编译器错误可以追溯到ostream_iterator 类的赋值运算符。它发生在*_Myostr &lt;&lt; _Val;
    猜你喜欢
    • 2018-11-26
    • 2023-01-20
    • 1970-01-01
    • 2013-07-29
    • 2016-05-17
    • 2016-06-22
    • 2015-11-07
    • 2010-09-06
    • 2014-10-04
    相关资源
    最近更新 更多