简体   繁体   English

模板类型推导中的隐式转换

[英]Implicit conversion in template type deduction

In this question the OP asks why his std::accumulate function is returning the wrong value. 在这个问题中 ,OP询问为什么他的std::accumulate函数返回错误的值。 The answer is because he passes in an int for his initial value, therefore making the calculations all int s rather than double s. 答案是因为他将int用作初始值,因此计算全部为int而不是double 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 ? 为什么在版本2中T仍然是int Because of implicit conversion? 因为隐式转换?

T is still being deduced, overwriting the default argument. 仍在推导T ,覆盖默认参数。 :) :)

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

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. 例如,如果要对较长的字符串中的char值求和。 Using safe_accumulate() as it is defined above makes specifying the result type a bit painful: 使用上面定义的safe_accumulate()会使指定结果类型有些safe_accumulate()

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM