我想定义一个用于打印类似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 ++的新手,所以我不知道这类东西的确切术语。这被称为“模板专业化”吗?
答案 0 :(得分: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));
}
答案 1 :(得分:2)
答案很简单。
函数中的类型名K
和V
没有依赖关系。所以删除它们并制作一般模板。它可用于map
和multimap
:
template <class AnyMap>
void PrintCollection(const AnyMap& map,
...
{
typedef typename AnyMap::const_iterator iter_type;
注意,使用template
s时,您不需要inline
个关键字。
答案 2 :(得分: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
非常通用且没有使用Key
和Value
类型的事实,您会更喜欢该解决方案。 OTOH,如果您的PrintCollection
还需要在将来的某个版本中打印该信息,那么您可能需要使用模板模板参数,该参数将这两种类型作为参数。