I tried to make a function that sums all elements of an std::vector
:
template<typename IteratorT>
auto sum(IteratorT first, IteratorT last) -> decltype(*first) {
decltype(*first) sum = 0;
for (; first != last; ++first)
sum += *first;
return sum;
}
and I got this error:
cannot convert from 'int' to 'int&'
Then after some research I found this: std::iterator_traits<IteratorT>::difference_type
. Changed my code to:
template<typename IteratorT>
auto sum(IteratorT first, IteratorT last) -> typename std::iterator_traits<IteratorT>::difference_type {
std::iterator_traits<IteratorT>::difference_type sum = 0;
for (; first != last; ++first)
sum += *first;
return sum;
}
and it did work, but I am not sure why and if it's a good solution or not. In conclusion I have two questions:
1) Why decltype(*first)
returns int&
and not int
as I expected
2) What exactly typename
before std::iterator_traits<IteratorT>::difference_type
does and why sum
function doesn't work if I remove it
decltype(*first)
returns a reference, as else we would not be able to write things like
*first = 7;
Regarding difference_type
it's not clear what you's trying to do. The word typename
is required in order to tell the compiler that a so called dependent type (the usual case is any type after a ::
) is a template and not a value.
Try this:
#include <type_traits>
template <
typename Iter,
typename Ret = typename std::decay<decltype(*std::declval<Iter>())>::type>
Ret f(Iter first, Iter last)
{
Ret sum {};
for (; first != last; ++first) { sum += *first; }
return sum;
}
There are two main problems:
The type of aa dereferenced iterator is a reference, it can be const
, and for a std::vector
it can be very different from the vector's item type.
When the item type is eg bool
, you don't want to do the sum in bool
type.
The following code is one solution:
#include <iterator> // std::iterator_traits
template< class Iter >
auto sum( Iter first, Iter last )
-> decltype( typename std::iterator_traits<Iter>::value_type() + 0 )
{
decltype( typename std::iterator_traits<Iter>::value_type() + 0 ) sum = 0;
for (; first != last; ++first)
sum += *first;
return sum;
}
#include <iostream>
#include <vector>
#include <utility>
using namespace std;
#define ITEMS( x ) begin( x ), end( x )
auto main()
-> int
{
vector<double> const v1 = {3, 1, 4, 1, 5};
cout << sum( ITEMS(v1) ) << endl;
vector<bool> const v2 = {0, 1, 1, 0, 1};
cout << sum( ITEMS( v2) ) << endl;
}
Note that you don't have to define your own sum
: there is std::accumulate
.
You did a random thing, which works randomly. distance_type
has nothing to do with your problem, it's a type which denotes the result of measuring a distance between two iterators. Since more often than not it is a integer type, you ended up being able to use it in your arithmetic.
The original issue was due to the fact that dereferencing an iterator returns a (const) pointer to the underlying object - and this is needed so that code like
*it = 10;
would do what you want it to do (or failed to compile for const iterators).
And the typename
keyword is required, but there are enough duplicates here on typename
usage here already.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.