C++ 模板类作为模板参数

C++ 模板类作为模板参数,c++,templates,C++,Templates,如何在容器和类型上定义函数模板 例如,重载插入运算符以流化向量、列表或前向迭代器容器的所有元素: using namespace std; #include <iostream> #include <vector> #include <list> //... //...the second argument is a container template-ed on type T //... template <typename T,templat

如何在容器和类型上定义函数模板

例如,重载插入运算符以流化向量、列表或前向迭代器容器的所有元素:

using namespace std;

#include <iostream>
#include <vector>
#include <list>


//...
//...the second argument is a container template-ed on type T
//...
template <typename T,template <typename U> class C>
ostream&
operator<<
  (ostream& p_os,const C<T>& p_c)
{
  for(typename C<typename T>::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
  {
    p_os.operator<<(*cit);
  }
  return p_os;
}

int
main
  ()
{
  vector<int> v;
  cout << v << endl;
  list<int> l;
  cout << l << endl;
  return 0;
}
使用名称空间std;
#包括
#包括
#包括
//...
//…第二个参数是基于类型T的容器模板
//...
模板
奥斯特雷姆&
运算符是具有两个模板类型参数的类模板:

template <class T, class Alloc = allocator<T> >
class vector;
或者:

template <typename T, template <typename...> class C>
ostream& operator<<(ostream& p_os, const C<T>& p_c);
模板

ostream&operator为什么不将容器类型作为模板参数传递,并从中找出元素类型?在示例代码中,您甚至不需要元素类型:

template <typename C>
ostream&
operator<<
  (ostream& p_os,const C& p_c)
{
  typedef typename C::value_type element_type; // if needed
  for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
  {
    p_os.operator<<(*cit);
  }
  return p_os;
}

艾伦·斯托克斯的方法很有效。下面的代码可以流式传输任何容器。我只需要为地图添加一个插入操作符

using namespace std;

#include <iostream>

#include <vector>
#include <list>
#include <forward_list>
#include <set>
#include <deque>
#include <array>
#include <map>
#include <unordered_map>

//...
//...needed for map types which are (key,value) pairs.
//...
template <typename K,typename V>
ostream&
operator<<
  (ostream& p_os,const pair<const K,V>& p_v)
{
  std::operator<<(p_os,'(');
  p_os << p_v.first;
  std::operator<<(p_os,',');
  p_os << p_v.second;
  std::operator<<(p_os,')');
  return p_os;
}

template <typename C, typename T = typename C::iterator>
ostream&
operator<<
  (ostream& p_os,const C& p_c)
{
  for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
  {
    typename C::value_type v = *cit;
    p_os << v;
    std::operator<<(p_os,",");
  }
  return p_os;
}

int
main
  ()
{
  vector<int> v;
  for(int i=0;i<4;++i)
  {
    v.push_back(i);
  }
  cout << v << endl;
  list<int> l;
  for(int i=0;i<4;++i)
  {
    l.push_back(i);
  }
  cout << l << endl;
  forward_list<int> fl = {0,1,2,3};
  cout << fl << endl;
  set<int> s;
  for(int i=0;i<4;++i)
  {
    s.insert(i);
  }
  cout << s << endl;
  deque<int> d;
  for(int i=0;i<4;++i)
  {
    d.push_back(i);
  }
  cout << d << endl;
  array<int,4> a = {0,1,2,3};
  cout << a << endl;
  unordered_map<int,int> um;
  for(int i=0;i<4;++i)
  {
    um[i] = i;
  }
  cout << um << endl;
  map<int,int> m;
  for(int i=0;i<4;++i)
  {
    m[i] = i;
  }
  cout << m << endl;
  return 0;
}
使用名称空间std;
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
//...
//…是(键、值)对的映射类型所需。
//...
模板
奥斯特雷姆&

操作符
vector
至少有两个模板参数-一个实现可以添加更多,只要它们有默认值。所以第一个版本是不可移植的。@AlanStokes我不相信你,标准是怎么说的?对不起,这条“常识”不是真的。它被提议但被拒绝:分配器有一个默认值,因此,如果默认分配器是可接受的,那么这种方法是不必要的。@silvermangb将向量与模板参数匹配是必要的。这种方法符合我的要求。我扩展了它,以支持流式传输所有容器类型”(尽管在没有一些enable_if技巧的情况下,将其用于这样的全局函数可能是不明智的,因为它将匹配任何参数。)“我尝试使用逗号分隔容器的条目,但编译器尝试使用该函数流式传输字符串。如何使用enable_if避免这种情况?请参阅编辑(实际上不使用
enable_if
)。有关更复杂、更强大的解决方案,请参阅。仍然不完全正确。导致运算符不明确,
string
是一个容器,所以它应该与之匹配。不过,我还是想为string找到一个解决方法。序列化任何容器操作符
template <typename C, typename T = typename C::value_type>
ostream&
operator<<
  (ostream& p_os,const C& p_c)
using namespace std;

#include <iostream>

#include <vector>
#include <list>
#include <forward_list>
#include <set>
#include <deque>
#include <array>
#include <map>
#include <unordered_map>

//...
//...needed for map types which are (key,value) pairs.
//...
template <typename K,typename V>
ostream&
operator<<
  (ostream& p_os,const pair<const K,V>& p_v)
{
  std::operator<<(p_os,'(');
  p_os << p_v.first;
  std::operator<<(p_os,',');
  p_os << p_v.second;
  std::operator<<(p_os,')');
  return p_os;
}

template <typename C, typename T = typename C::iterator>
ostream&
operator<<
  (ostream& p_os,const C& p_c)
{
  for(typename C::const_iterator cit=p_c.begin();cit!=p_c.end();++cit)
  {
    typename C::value_type v = *cit;
    p_os << v;
    std::operator<<(p_os,",");
  }
  return p_os;
}

int
main
  ()
{
  vector<int> v;
  for(int i=0;i<4;++i)
  {
    v.push_back(i);
  }
  cout << v << endl;
  list<int> l;
  for(int i=0;i<4;++i)
  {
    l.push_back(i);
  }
  cout << l << endl;
  forward_list<int> fl = {0,1,2,3};
  cout << fl << endl;
  set<int> s;
  for(int i=0;i<4;++i)
  {
    s.insert(i);
  }
  cout << s << endl;
  deque<int> d;
  for(int i=0;i<4;++i)
  {
    d.push_back(i);
  }
  cout << d << endl;
  array<int,4> a = {0,1,2,3};
  cout << a << endl;
  unordered_map<int,int> um;
  for(int i=0;i<4;++i)
  {
    um[i] = i;
  }
  cout << um << endl;
  map<int,int> m;
  for(int i=0;i<4;++i)
  {
    m[i] = i;
  }
  cout << m << endl;
  return 0;
}