在这个question中,OP询问他的std::accumulate
函数返回错误值的原因。答案是因为他传递int
的初始值,因此计算所有int
而不是double
s。我有两个版本:
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;
}
为什么版本2 T
仍为int
?因为隐式转换?
答案 0 :(得分:3)
T
仍然被推断,覆盖了默认参数。 :)
你想要这个:
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 :(得分:1)
已经说明了当前问题的答案:如果类型可以从参数列表中推断出来,那么它将被推导出来。使用的类型是嵌套类型可以防止它被推断出来:
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);
}
但是,在某些情况下,需要指定算法的结果类型。例如,如果要在冗长的字符串中对char
值求和。使用上面定义的safe_accumulate()
会使结果类型指定有点痛苦:
std::string s("hello, world");
std::cout << safe_accumulate<std::string::iterator, long>(s.begin(), s.end(), 0) << '\n';
可以通过将结果类型放在第一位的方式完成实现:
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);
}
现在算法可以更方便的方式使用,即算法的实现者为了用户的利益提供了一些更复杂的实现:
std::cout << safe_accumulate<long>(s.begin(), s.end(), 0) << '\n';