【问题标题】:How to write a generalized (template) container out-putter如何编写通用(模板)容器输出器
【发布时间】:2017-01-17 18:25:43
【问题描述】:

我正在努力加快“现代”C++ 的速度,尤其是使用模板。我有一个覆盖

我的问题 - 有没有办法为多种容器类型编写类似于下面代码的模板?

template <typename T>
std::ostream& operator <<(ostream& os, const vector<T>& v)
{
  os << "\n";
  for( auto x : v ) { os << "\n\t" << x; }
  os << "\n";
  return os;
}

只要 T 有

我也意识到,以通用方式为所有类型覆盖容器的输出可能是一个坏主意(或至少是粗鲁的)。所以最终上面的模板代码将类型名硬编码/限制为“Point”和一个模板化容器。


好的,根据 AndyG 的建议,我有以下完整代码:

#include <iostream>
#include <map>
#include <vector>

using namespace std;


struct Point {
  double x, y, z;

  Point() : x(0), y(0), z(0) {};
  Point(double a, double b, double c) : x(a), y(b), z(c) {}
  Point(double a[]) : x(a[0]), y(a[0]), z(a[0]) {}

  friend std::ostream& operator <<(ostream& os, const Point&p)
  {
    os << p.x << ", " << p.y << ", "<< p.z;
    return os;
  }

};

template <template<class> class C, class... T>
std::ostream& operator <<(ostream& os, const C<T...>& v)
{
  os << "\n";
  for( auto x : v ) { os << "\n\t" << x; }
  os << "\n";
  return os;
}

vector<Point> vp = { { 1, 2, 3 },
                     { 5, 7, 4 },
                     { 8, 2, 5 }
};

int main(int argc, char* argv[])
{
  cout << vp[0]; // works
  cout << vp;    // dosen't work,
}

但仍然没有运气。编译器无法将 operator

在我的第一篇文章之前,我尝试了template &lt;template&gt; 的许多变体,结果大致相同。我可以得到一个可以编译的模板,但是编译器无法匹配运算符函数并使用该模板。

我不知道可变参数模板包,这显然是个好主意,但不能解决问题。

【问题讨论】:

  • template &lt;template&lt;class&gt; class C, class... T&gt; std::ostream&amp; operator &lt;&lt;(ostream&amp; os, const C&lt;T...&gt;&amp; v) 但你肯定会遇到一些问题。像std::map 这样的关联容器很难与像std::vector 这样的非关联容器混在一起
  • 此处描述了类似的工作:stackoverflow.com/questions/4850473/…
  • 而且,正如你所说,添加一个匹配所有 T 的模板是非常粗鲁的,包括我的类型。这就是std::vector 还没有的原因之一。
  • 是的,这确实是一个相当蹩脚的用例并且存在问题。然而,我真正想做的是了解我理解的和我不理解的。

标签: c++ templates


【解决方案1】:

好的,AndyG 让我走上了正轨,我想我明白发生了什么。

以下代码不起作用,因为 std::container 模板还有一个分配器参数,该参数具有默认值,您很少需要使用它。因此,我们认为大多数容器模板只采用它们将包含的类型/类。

这个

template < template <class> class C, class... T>
std::ostream& operator <<(ostream& os, const C<T...>& v)
{ ... }

不起作用,因为我们将在 operatorC 的模板接受两个参数而不是一个。因此编译器不会找到匹配项。

这将起作用:

template < template <class, class> class C, class... T>
std::ostream& operator <<(ostream& os, const C<T...>& v)

因为编译器可以将vector&lt;Point, Alloc&gt; 匹配到我们选择调用Ctemplate&lt;class, class&gt;。然后它可以使用我们的函数模板为operator &lt;&lt; 生成重载。

请注意,这种方法通常存在许多问题。 template &lt;class, class&gt; 不会匹配带有 4 个参数的 std::map ,其中 2 个是默认参数。更糟糕的是,它匹配任何两个可能是也可能不是容器的参数模板。

我们可以通过使用 varg 参数来解决这个问题:template &lt;class, class...&gt; 但是我们仍然搞砸了,因为现在 std::pairs,而编译器不知道如何处理 cout &lt;&lt;

因此,虽然这对我更好地理解模板是一个有用的练习,但不要这样做。

这个链接有一个整洁的容器漂亮的打印库:Pretty-print C++ STL containers

【讨论】:

  • 我的意思是在我原来的评论中说template&lt;class...&gt; class C, class... T&gt;,对不起。
  • NP - (对我而言)努力找出您的答案不起作用的原因是值得的。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-04-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多