假设我有一个模板函数来计算地图元素的总和,如下所示:
template <class A, class B> double Total(const map<A, B>& cntr)
{
map<A, B>::const_iterator iter;
double total = 0;
for (iter = cntr.begin(); iter != cntr.end(); ++iter)
total += iter->second;
return total;
}
只要B是数字类型,它就能正常工作;但是,显然如果你传递了map<int, string>
之类的引用,它就行不通了。
我想知道如何测试地图非关键部分中包含的类型,以便我可以通过异常或其他内容。我尝试使用isdigit()但似乎无法获得正常工作的版本。
编辑:我对测试的预期用途是添加功能,以便总是使用int类型来计算总数,因此我可以传递map<int, string>
或map<string, int>
并且它将始终计算int类型。
答案 0 :(得分:2)
您可以在C ++ 11或boost中使用类型特征。
#include <type_traits>
template <class A, class B> double Sum(const map<A, B>& cntr)
{
static_assert(std::is_arithmetic<B>::value, "Invalid type!");
map<A, B>::const_iterator iter;
double total = 0;
for (iter = cntr.begin(); iter != cntr.end(); ++iter)
total += iter->second;
return total;
}
请记住,即使没有断言,无效的类型也无法编译。
答案 1 :(得分:1)
您的代码限制性太强,因为map
需要两个以上的模板参数,您也可能希望支持其他类型的unordered_map
。我建议使用这样的模板:
template <typename Map>
typename Map::mapped_type accumulate(Map const & m)
{
typedef typename Map::mapped_type type;
type result;
// if you like:
static_assert(std::is_arithmetic<type>::value, "Mapped type cannot be accumulated over.");
for (auto it = m.cbegin(), end = m.cend(); it != end; ++it) // or your favourte loop construct
{
result += it->second;
}
return result;
}
实际上你也可以通过连接来累积字符串,但我已经添加了算术类型的静态断言检查,以防你想要限制它。或者,如果要将字符串转换为数字,可以编写一个更通用的“添加”包装器,在字符串上使用std::stoul
或std::stod
。
也可以轻松提供非零起始值。
或者,整个事情可以表示为使用std::accumulate
和lambda的单行:
auto result = std::accumulate(m.cbegin(), m.cend(), 0.0,
[](double d, Map::value_type const & p) -> double { return d + p.second; });
答案 2 :(得分:0)
实际上,如果你试图用类型的参数调用你的代码,那么你的代码就不会编译,因为opertor + =(double a,const B&amp; o)是未定义的,所以在你提到的情况下你是安全的。 / p>
答案 3 :(得分:0)
好吧,您可以尝试使用static_cast
运算符来检测参数是否可以转换为数字类型。例如,一个函数
template <class T> void func (T arg) {
double u = static_cast<double> (arg);
//do foo
}
如果arg
不是数字类型,编译器必须执行编译时错误。