2

In this question the OP asks why his std::accumulate function is returning the wrong value. The answer is because he passes in an int for his initial value, therefore making the calculations all ints rather than doubles. I have two versions:

template <class InputIterator, class T>
auto accumulate (InputIterator first, InputIterator last, T init)
{
  typedef typename std::iterator_traits<InputIterator>::value_type vt;
  vt init2 = vt(init);
  // ...
  return init2;
}

template <class InputIterator, class T = typename std::iterator_traits<InputIterator>::value_type>
T not_working (InputIterator first, InputIterator last, T init)
{
// ...
return init;
}

Why in version 2 is T still an int? Because of implicit conversion?

Community
  • 1
  • 1

2 Answers2

3

T is still being deduced, overwriting the default argument. :)

You want this:

template <class InputIterator>
typename std::iterator_traits<InputIterator>::value_type
working(InputIterator first, InputIterator last,
        typename std::iterator_traits<InputIterator>::value_type init) {
    return init;
}
1

The answer to the immediate question was already stated: if the type can be deduced from the argument list, it will be deduced. Making the used type a nested type prevents it from being deduced:

template <typename T>
struct identity {
    typedef T type;
};
template <typename It, typename T = typename std::iterator_traits<It>::value_type>
T safe_accumulate(It begin, It end, typename identity<T>::type sum) {
    return std::accumulate(begin, end, sum);
}

In some situations it is, however, desirable to specify the result type of the algorithm. For example, if you want to sum the char values in a lengthy strings. Using safe_accumulate() as it is defined above makes specifying the result type a bit painful:

std::string s("hello, world");
std::cout << safe_accumulate<std::string::iterator, long>(s.begin(), s.end(), 0) << '\n';

The implementation can be done in a way which puts the result type first:

template <typename T = void, typename It>
typename std::conditional<std::is_same<T, void>::value,
    typename std::iterator_traits<It>::value_type,
    T>::type
safe_accumulate(It begin, It end,
                typename std::conditional<std::is_same<T, void>::value,
                    typename std::iterator_traits<It>::value_type,
                    T>::type sum) {
    return std::accumulate(begin, end, sum);
}

Now the algorithm can be used in a more convenient way, i.e., the implementer of the algorithm provided a somewhat more complicated implementation for the benefit of its users:

std::cout << safe_accumulate<long>(s.begin(), s.end(), 0) << '\n';
Dietmar Kühl
  • 150,225
  • 13
  • 225
  • 380