我设置了两个模板函数,它们为不同的STL容器获取总和:一个用于列表和向量,另一个用于映射。
请参阅第二个模板函数定义的注释行(1)和(2)。注释掉的代码(= 2)也可以正常工作,所以我不知道哪一个是更推荐的语法。
此外,每个方法如何调用(我在评论中恰当地猜到了)?要说(1)是一个函数模板重载似乎不够,因为它在关键字'template'之后缺少typename参数。也就是说,它应该像template<typename T>
结合(1),以便将方法作为函数模板重载调用,我猜。请给我他们正确的名字。
template <typename T> // T : container
double Sum(const T &l) // get Container
{
double sum = 0;
T::const_iterator i;
for (i = l.begin(); i != l.end(); ++i) { sum += *i; }
return sum;
}
template <> // get container
double Sum(const map<string, double> &m) // (1) function template overloading
// double Sum<map<string, double> >(const map<string, double> &m) // (2) explicit specialization
{
double sum = 0;
map<string, double>::const_iterator i; // obtain Iterator from Container
for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data)
return sum;
}
答案 0 :(得分:1)
两者都是显式专业化语法
template <> double Sum(const map<string, double> &m);
template <> double Sum<map<string, double> >(const map<string, double> &m)
第一个让编译器推导出参数,而第二个让你明确。
当编译器无法推断出
的所有模板参数时,第二个是必需的template <typename T> std::string getNameType();
template <> std::string getNameType<int>() { return "int"; }
或消除歧义哪个模板功能专门化
template <typename T> void foo(T);
template <typename T> void foo(T*); // overload, not specialization
//template <> void foo(int*); // Error: do you mean T = int for foo(T*) or T = int* for foo(T)
template <> void foo<int*>(int*); // specialize foo(T)
template <> void foo<int>(int*); // specialize foo(T*)
通常最好使用重载而不是函数的特化,因此对于您的示例:
template <typename Key>
double Sum(const std::map<Key, double> &m)
{
double sum = 0;
for (const auto& p : m) { sum += p.second; } return sum;
}
答案 1 :(得分:0)
对于具体类型,您最好只是定义一个非模板重载:
double Sum(const std::map<std::string, double> &m) // (1) function template overloading
// double Sum<map<string, double> >(const map<string, double> &m) // (2) explicit specialization
{
double sum = 0;
std::map<std::string, double>::const_iterator i; // obtain Iterator from Container
for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data)
return sum;
}
模板对于通用函数更有用:
//
// sum any map's arithmetic mapped values
//
template<class K, class V, class C, class A>
typename std::map<K, V, C, A>::mapped_type
Sum(const std::map<K, V, C, A> &m) // (1) function template overloading
{
using map_type = std::map<K, V, C, A>;
using mapped_type = typename map_type::mapped_type;
using const_iterator = typename map_type::const_iterator;
mapped_type sum = 0;
const_iterator i; // obtain Iterator from Container
for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data)
return sum;
}
...或者迂腐一般(c ++ 14)......
namespace notstd {
template< class... >
using void_t = void;
}
template< class, class = notstd::void_t<> >
struct supports_mapped_type : std::false_type { };
template< class T >
struct supports_mapped_type<T, notstd::void_t<typename T::mapped_type>> : std::true_type { };
template< class, class = notstd::void_t<> >
struct supports_const_iterator : std::false_type { };
template< class T >
struct supports_const_iterator<T, notstd::void_t<typename T::const_iterator>> : std::true_type { };
template<class T> static constexpr bool IsMaplike = supports_mapped_type<T>() and supports_const_iterator<T>();
template<class MapLike,
std::enable_if_t<
IsMaplike<MapLike> and std::is_arithmetic<typename MapLike::mapped_type>()
>* = nullptr>
typename MapLike::mapped_type
Sum(const MapLike &m) // (1) function template overloading
{
using map_type = MapLike;
using mapped_type = typename map_type::mapped_type;
using const_iterator = typename map_type::const_iterator;
mapped_type sum = 0;
const_iterator i; // obtain Iterator from Container
for (i = m.begin(); i != m.end(); i++) { sum += i->second; } // sum. ('first' is index, 'second' is data)
return sum;
}
现在很高兴总结:
std::unordered_map<std::string, int>
,和
std::map<std::string, int>
,
但不是
std::map<int, std::string>
答案 2 :(得分:0)
我没有完全理解你的问题,因为你的代码似乎没问题,但我会尝试回答。当您手动编写具有相同名称但不同参数类型的多个函数时,函数重载是一种方法。例如:
double Sum(const std::vector<double>& l) {
//...
}
double Sum(const std::list<double>& l) {
//...
}
double Sum(const std::deque<double>& l) {
//...
}
在您的示例中,您编写了一个函数模板:
template <typename T>
double Sum(const T &l) //...
和模板专业化:
template <>
double Sum(const map<string, double> &m) //...
哪个更好?这取决于你的情况。看看,有了函数重载,你应该自己编写代码,而在模板的情况下,编译器会为你做这些!
例如,您的一般案例模板适用于vector
,list
,queue
,deque
以及任何其他可能暂时不存在的兼容容器模板创建。编译器仅为那些用于实例化模板的类型生成代码。如果您尝试使用不兼容的类型对其进行实例化,则会出现编译错误。并且只有使用map<string, double>
实例化它(对于一般案例模板无效),编译才会成功,因为将选择专门化来生成代码。
正如@RichardHodges所提到的,专业化可能对你的案件来说太过分了;非模板重载应该足够了。