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