1

我想定义一个通用函数来打印std::map类似类型的内容。我最初的尝试是这样的功能:

template <class K, class V>
inline void PrintCollection(const std::map<K,V>& map,
                            const char* separator="\n",
                            const char* arrow="->",
                            const char* optcstr="") {
  typedef typename std::map<K,V>::const_iterator iter_type;
  std::cout << optcstr;
  for (iter_type begin = map.begin(), it = begin, end = map.end();
       it != end; ++it) {
    if (it != begin) {
      std::cout << separator;
    }
    std::cout << it->first << arrow << it->second;
  }
  std::cout << std::endl;
}

效果很好。当我尝试将这个函数再推广一步,即让它适用于std::multimap类型时,编译器会生气。我尝试了几种方法std::map在函数定义中进行泛型,例如:

template <class M, class K, class V>
inline void PrintCollection(const M<K,V>& map,
                            const char* separator="\n",
                            const char* arrow="->",
                            const char* optcstr="") {
  typedef typename M<K,V>::const_iterator iter_type;
  std::cout << optcstr;
  for (iter_type begin = map.begin(), it = begin, end = map.end();
       it != end; ++it) {
    if (it != begin) {
      std::cout << separator;
    }
    std::cout << it->first << arrow << it->second;
  }
  std::cout << std::endl;
}

没有成功。

我如何概括我上面定义的这个函数?

更清楚地说,我已经为在这个函数之前定义的类向量类定义了一个函数。它像是

template <class T>
inline void PrintCollection(const T& collection,
                            const char* separator="\n",
                            const char* optcstr="") {
  typedef typename T::const_iterator iter_type;

  std::cout << optcstr;

  for (iter_type begin = collection.begin(), it = begin, end = collection.end();
       it != end;
       ++it) {
    if (it != begin) {
      std::cout << separator;
    }
    std::cout << *it;
  }

  std::cout << std::endl;
}

所以我想要实现它来使这个功能专门用于类似地图的类。我是 C++ 的新手,所以我不知道这类东西的确切术语。这是否称为“模板专业化”?

4

3 回答 3

4

像 stdlib 那样做,并在你的算法接口中使用迭代器。这是最通用的解决方案。

template<class Iter>
void PrintCollection(Iter first, Iter last,
                     const char* separator="\n",
                     const char* arrow="->",
                     const char* optcstr="") 
{
    typedef Iter iter_type;
    std::cout << optcstr;
    for (iter_type begin = first, it = begin, end = last;
        it != end; ++it) {
    if (it != begin) {
        std::cout << separator;
    }
    std::cout << it->first << arrow << it->second;
    }
    std::cout << std::endl;
}


int main()
{
    vector<pair<int, int>> collection;
    map<int, int> collection2;
    pair<int, int> collection3[3];

    PrintCollection(begin(collection), end(collection));
    PrintCollection(begin(collection2), end(collection2));
    PrintCollection(begin(collection3), end(collection3));
}
于 2012-06-25T06:37:27.177 回答
2

答案相当简单。

不依赖于类型名KV函数。所以删除它们并制作一个通用模板。它可以同时用于mapmultimap

template <class AnyMap>
void PrintCollection(const AnyMap& map,
  ...
{
  typedef typename AnyMap::const_iterator iter_type;

附带说明,使用templates,您不需要inline关键字。

于 2012-06-25T06:46:53.310 回答
1

您可以使用模板模板参数

template<template<class, class> class M, class K, class V>
inline void PrintCollection(const M<K, V>& map, /* rest as before */)
{
    // rest as before
}

int main()
{
    std::map<int, int> m1;
    std::multi_map<int, int> m2;

    // fill both maps

    PrintCollection(m1);
    PrintCollection(m2);
}

但正如 hansmaad 所指出的,您也可以使用一对迭代器而不是容器作为参数。一般来说,如果您PrintCollection的解决方案非常通用并且没有利用它具有KeyandValue类型的事实,您会更喜欢该解决方案。OTOH,如果您PrintCollection还需要在将来的某个版本中打印该信息,那么您可能需要使用将这两种类型作为参数的模板模板参数。

于 2012-06-25T06:38:02.533 回答