自动识别合适的类型,足够大且足够精确,以保存容器中所有元素的总和

时间:2016-09-08 07:44:10

标签: c++ c++11 auto decltype

(此问题已从原版中进行了大幅度编辑,未改变原始问题的真实意图)

如果我们将vector<int>中的所有元素相加,那么答案可能会溢出,需要intmax_t之类的内容来准确 存储答案而不会溢出。但intmax_t不适合vector<double>

我可以手动指定类型:

template<typename>
struct sum_traits;

template<>
struct sum_traits<int> {
    typedef long accumulate_safely_t;
};

然后按如下方式使用它们:

template<typename C>
auto sum(const C& c) {
    sum_traits<decltype(c.begin())> :: accumulate_safely_t> r = 0;
    for(auto &el: c)
        r += el;
    return r;
}

我的问题:是否可以自动识别合适的类型,大而准确的类型,因此我不必通过类型特征手动指定每个类型?

3 个答案:

答案 0 :(得分:4)

您的代码的主要问题是self.view.layer.backgroundColor = [UIColor clearColor].CGColor; 等同于auto r = 0。这不是你的C ++ 98代码的工作方式。通常,您无法找到完美的目标类型。您的代码只是int r = 0的变体,因此我们可以看一下标准如何解决这个问题:它允许您传递累加器的初始值,还有它的类型:std::accumulate

答案 1 :(得分:3)

假设:

  

如果我们将向量中的所有元素相加,那么答案可能会溢出,需要像intmax_t那样准确地存储答案而不会溢出。

问题:

  

我的问题:是否可以自动识别合适的类型,大而准确的类型,因此我不必通过类型特征手动指定每个类型?

这里的问题是你想要获取运行时数据(向量)并从中推导出一种类型(编译时的东西)。

由于类型推导是一个编译时操作,我们必须在编译时只使用我们可用的信息来做出这个决定。

我们在编译时获得的唯一信息(除非您提供更多信息)是var sortedKeys = Array(dict.keys).sort({dict[$0] > dict[$1]}) std::numeric_limits<int>::max()

在这个阶段你甚至没有std::numeric_limits<std::vector<int>::size_type>::max(),因为它不是std::vector<int>::max_size()的强制要求。你也不能依赖constexpr,因为它是:

  1. 会员功能
  2. 可选的
  3. 在c ++ 17中弃用
  4. 所以我们留下的是最大可能的总和:

    std::vector<int>::allocator_type::max_size()

    我们现在可以使用编译时析取来找到一个合适的整数(如果存在这样的整数)(涉及std::numeric_limits<int>::max() * std::numeric_limits<std::vector<int>::size_type>::max()的内容)

    这不会使类型适应运行时条件,但它至少会适应您正在编译的体系结构。

    这样的事情:

    std::conditional

答案 2 :(得分:1)

您可以在C ++ 14中使用return type deduction,如下所示:

template<typename C>
auto sum(const C& c) {
    auto r = 0;
    for(auto &el: c)
        r += el;
    return r;
}

在C ++ 11中,考虑到您的C ++ 98代码,您可以使用以下代码:

template<typename C>
auto sum(const C& c) -> typename C::value_type {
    auto r = 0;
    for(auto &el: c)
        r += el;
    return r;
}

但是,正如评论中所指出的,auto r = 0;在编译时仍会解析为int。正如在另一个答案中提出的那样,您可能希望将初始值类型(以及返回值类型)设置为模板参数:

template<typename C, typename T>
T sum(const C& c, T init) {
    for(auto &el: c)
        init += el;
    return init;
}

// usage

std::vector<std::string> v({"Hello ", "World ", "!!!"});
std::cout << sum(v, std::string{});