Referring, for example, to this snippet from cplusplus.com:
template <class InputIterator, class T>
typename iterator_traits<InputIterator>::difference_type
count(InputIterator first, InputIterator last, const T& val)
{
typename iterator_traits<InputIterator>::difference_type ret = 0;
while (first!=last) {
if (*first == val)
++ret;
++first;
}
return ret;
}
The question is why use iterator_traits
in this context rather than taking in another template argument as shown here:
template <class InputIterator, class T, class DiffType>
DiffType count(InputIterator first, InputIterator last, const T& val)
{
DiffType ret = 0;
while (first!=last) {
if (*first == val)
++ret;
++first;
}
return ret;
}
The suggestion you proposed in the comments - having the function take in another template argument - will not work as you intended. Here's the code you've suggested:
template <class InputIterator, class T, typename DiffType>
DiffType count(InputIterator first, InputIterator last, const T& val)
{
DiffType ret = 0;
while (first!=last) {
if (*first == val)
++ret;
++first;
}
return ret;
}
The problem with this code is that this no longer compiles:
std::vector<int> v = /* ... */;
auto numElems = count(v.begin(), v.end(), 137); // <--- Error!
The issue here is that in order to invoke a function template, every template argument either has to be deducible from the argument types or explicitly specified by the caller. Here, the type DiffType
can't be deduced from the argument types (the InputIterator
and T
types can be inferred from the two arguments, but from the signature alone there's no context), so this call would fail with a compiler error. The use of std::iterator_traits
here is a general template pattern for extracting information about an iterator from the iterator type itself.