Search code examples
c++c++11autodecltype

Automatically identify a suitable type, large enough and precise enough, to hold the sum of all elements in a container


(This question has been dramatically edited from the original, without changing the real intent of the original question)

If we add up all the elements in a vector<int>, then the answer could overflow, requiring something like intmax_t to store the answer accurately and without overflow. But intmax_t isn't suitable for vector<double>.

I could manually specify the types:

template<typename>
struct sum_traits;

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

and then use them as follows:

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;
}

My questions: Is it possible to automatically identify a suitable type, a large and accurate type, so I don't have to manually specify each one via the type trait?


Solution

  • You can use return type deduction in C++14 just like this:

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

    In C++11, considering your C++98 code, you may use the following:

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

    But, as pointed in the comments, auto r = 0; will still resolve to int at compile time. As proposed in an other answer, you may want to make the initial value type (and so the return value type) a template parameter as well:

    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{});