我怎样才能以通用的方式打印任何容器的内容?

时间:2009-07-20 15:21:21

标签: c++ templates stl operator-overloading

我正在尝试使用C ++模板编写一段有趣的代码。

#include <iostream>
#include <vector>

template <class Container>
std::ostream& operator<<(std::ostream& o, const Container& container)
{
    typename Container::const_iterator beg = container.begin();

    o << "["; // 1

    while(beg != container.end())
    {
        o << " " << *beg++; // 2
    }

    o << " ]"; // 3

    return o;
}

int main()
{
    std::vector<int> list;

    list.push_back(0);
    list.push_back(0);

    std::cout << list;

    return 0;
}

以上代码无法编译:)

在1,2,3处产生相同的错误:错误C2593:'operator&lt;&lt;'含糊不清

我想要做的就是重载&lt;&lt;操作员使用任何容器。那有意义吗 ?怎么可能呢?如果可能的话,如果不是为什么?

编辑::感谢您的更正:)'某事'是一个很好的解决方案。

我很好奇,如果我们可以使用C ++ 0x概念,这种歧义 - 如Neil解释的那样 - 会消失吗?

7 个答案:

答案 0 :(得分:7)

您可以限制您的运营商&lt;&lt;通过指定Container模板参数本身是模板化的,仅应用于模板化容器。由于C ++ std容器也有一个allocator模板参数,你还必须将它包含在Container的模板参数中。

template
    < typename T
    , template<typename ELEM, typename ALLOC=std::allocator<ELEM> > class Container
    >
std::ostream& operator<< (std::ostream& o, const Container<T>& container)
{
    typename Container<T>::const_iterator beg = container.begin();

    o << "["; // 1

    while(beg != container.end())
    {
        o << " " << *beg++; // 2
    }

    o << " ]"; // 3

    return o;
}

int main()
{
    std::vector<int> list;

    list.push_back(0);
    list.push_back(0);

    std::cout << list;

    return 0;
}

答案 1 :(得分:4)

新定义的operator<<不仅匹配容器,还匹配任何其他类型,如整数和字符串。这就是编译器在需要找到匹配的operator<<来输出"["时抱怨含糊不清的原因。

解决此问题的一种方法是重命名输出函数:

template <class Container>
std::ostream& container_out(std::ostream& o, const Container &container) {
  // ...
}

然后,您可以为要打印的所有容器添加简单包装器以启用operator<<

template<typename T>
std::ostream& operator<<(std::ostream& o, const std::vector<T> &container) {
  return container_out(o, container);
}

template<typename T>
std::ostream& operator<<(std::ostream& o, const std::map<T> &container) {
  return container_out(o, container);
}

答案 2 :(得分:3)

错误是什么?我看到一个,你需要一个类型名称:

typename Container::iterator beg = container.begin();

这里发生的事情是编译器在第一次阅读时对Container一无所知。所以我们必须给它一点帮助并告诉它迭代器将是一个类型(从语法上讲它可以是类范围内的任何有效名称,所以函数,变量,......)。编写模板方法时,任何依赖于模板类型的类型都必须指定它是具有关键字typename的类型。

答案 3 :(得分:2)

您的操作员介绍了它自己的模糊性 - 它本身可以用于打印它试图打印的东西。我的建议:

  • 使用命名函数,而不是operatr
  • 通过const引用传递容器(但这与问题无关)

答案 4 :(得分:1)

好的,现在你的模板会造成混乱。编译器无法在您的运算符和您期望的运算符之间做出决定。

答案 5 :(得分:1)

可能不像你发布的那样通用(你需要传递包含的类型),并且最后还留下了一个额外的分隔符,但你可以使用STL:

std::vector<int> v;
v.push_back( 10 );
v.push_back( 20 );

std::cout << "[";
std::copy( v.begin(), v.end(), std::ostream_iterator<int>( std::cout, " " ) );
std::cout << "]";

将输出:

  

[10 20]

请注意,额外的分隔符位于序列的末尾,并且[和第一个元素之间没有初始空格。

答案 6 :(得分:0)

http://blog.csdn.net/cqdjyy01234/article/details/19234329可能是一个很好的解决方案。它适用于STL容器和C风格的数组。