4

请考虑以下代码。我正在尝试将向量的向量输出到 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>&&. 可能我还不够了解。有没有更好的方法来做到这一点?

提前致谢。

4

2 回答 2

8

你得到的错误有点误导。当我试图编译你的程序时,我不得不深入挖掘模板呕吐物,我最终得到了我认为正在发生的事情:

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 命名空间中查找模板 vector<> 的重载(因为这是 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命名空间中使用它。

这就是为什么您使用全局声明的 operator << 在全局命名空间中可以正常工作,但不能在std命名空间内正常工作。命名空间已经有与您尝试提供的std重载名称相同的东西,因此重载对std. 如果您可以使用 using 声明,那么情况会有所不同。

于 2012-05-08T15:20:55.943 回答
4

您需要这个实用程序库:


如果您想自己执行此操作(以便自学),则需要将两个重载定义为:

  • 对于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
于 2012-05-08T15:11:50.950 回答