将矢量的矢量打印到ostream

Print vector of vectors to ostream

本文关键字:ostream 打印      更新时间:2023-10-16

请考虑以下代码。我正在尝试将向量向量输出到ostream。

#include <iterator>
#include <iostream>
#include <string>
#include <vector>
#include <algorithm>
template<typename T>
std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) {
    using namespace std;
    copy(v.begin(), v.end(), ostream_iterator<T>(os, "n"));
    return os;
}
int main() {
    using namespace std;
    vector<string> v1;
    cout << v1;
    vector<vector<string> > v2;
    cout << v2;
    return 0;
}

我输出字符串向量的语句有效。我输出字符串向量向量的那个没有。我正在使用 g++ 4.7.0。我已经尝试过w/&w/o-std=c++11标志。在 C++11 模式下,它在半页错误中给了我这一行。

error: cannot bind 'std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >::ostream_type {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'

我想我不明白这意味着什么。有人可以向我解释一下吗?我或多或少知道什么是右值引用,但我不明白为什么std::basic_ostream<char>不会绑定到std::basic_ostream<char>&&.也许我不够了解它。有没有更好的方法可以做到这一点?

提前谢谢。

您遇到的错误有点误导。 当我尝试编译你的程序时,我不得不深入研究模板呕吐物,最终我得到了我认为发生的事情:

error: no match for 'operator<<' in '*((std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >*)this)->std::ostream_iterator<std::vector<std::basic_string<char> >, char, std::char_traits<char> >::_M_stream << __value'

基本上,当您调用复制算法时,它使用输出迭代器,该迭代器使用命名空间 std 中的 <<运算符。 到达那里后,查找指示它尝试在 std 命名空间中查找模板向量的重载<>因为那是 IT 所在的位置(。

因此,您需要做的是在命名空间 std 中为矢量模板声明流运算符。 用namespace std {}包围你的代码,看看会发生什么......

应该注意的是,你所做的基本上是修改std::vector<>并向其添加以前不存在的行为。 这样做是非标准的、未定义的,并且很容易妨碍您。 您可以考虑其他选择。


我错了,这是一个 koenig 查找的东西。 不是,问题是名称隐藏类似于类中发生的情况,在这里您声明了基中某些内容的重载(而不是覆盖(。

标准命名空间声明多个"<<"运算符。 这些基本上是名为 operator << 的函数。 从本质上讲,您拥有的是:

void fun(int);
namespace Test {
  void fun() { fun(3); }
}
int main() {
    Test::fun();
}

请注意,可以使用全局命名空间中的fun(int),也可以使用其中没有任何名为 fun 的函数的命名空间。 不能从 Test 命名空间使用它。

这就是为什么全局声明运算符<<的使用在全局命名空间中工作正常,但在std命名空间中则不能正常工作的原因。 std命名空间已经具有与您尝试提供的重载命名相同的内容,因此重载对std中的所有内容都是隐藏的。 如果你能在那里放一个使用声明,事情就会有所不同。

您需要此实用程序库:

  • 漂亮的印刷C++ STL 容器

如果你想自己做这件事(以便自学(,那么你需要将两个重载定义为:

  • 对于std::vector<T>

    template<typename T>
    std::ostream &operator <<(std::ostream &os, const std::vector<T> &v) {
       using namespace std;
       copy(v.begin(), v.end(), ostream_iterator<T>(os, "n"));
       return os;
    }
    
  • 对于std::vector<std::vector<T>>

    template<typename T>
    std::ostream &operator <<(std::ostream &os, const std::vector<std::vector<T>> &v) {
       using namespace std;
       //NOTE: for some reason std::copy doesn't work here, so I use manual loop
       //copy(v.begin(), v.end(), ostream_iterator<std::vector<T>>(os, "n"));
       for(size_t i = 0 ; i < v.size(); ++i)
            os << v[i] << "n";
       return os;
    }
    

如果您有这些重载,那么它们将一起递归处理这些情况:

std::vector<int>  v;
std::vector<std::vector<int>>  vv;
std::vector<std::vector<std::vector<int>>>  vvv;
std::vector<std::vector<std::vector<std::vector<int>>>>  vvvv;
std::cout << v << std::endl; //ok
std::cout << vv << std::endl; //ok
std::cout << vvv << std::endl; //ok
std::cout << vvvv << std::endl; //ok