如何测试地图中包含的类型

时间:2012-02-05 15:49:57

标签: c++ templates

假设我有一个模板函数来计算地图元素的总和,如下所示:

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类型。

4 个答案:

答案 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::stoulstd::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不是数字类型,编译器必须执行编译时错误。