Reputation: 23644
I migrate my project from VC++ 2015 to VC++ 2017. I have my own implementation of iterator. It has forward-only operations set:
template <class Container>
struct NodeTableIterator
{
typedef NodeTableIterator<Container> this_t;
this_t& operator ++();
this_t operator ++(int);
};
Somewhere in code I use it for std::copy
std::copy(tbl.begin(), tbl.end(),
std::ostream_iterator<int>(std::cout, ", "));
This line perfectly worked in VC++2015 but fails in 2017 just because:
error C2784: 'unknown-type std::operator -(const std::move_iterator<_RanIt> &,const std::move_iterator<_RanIt2> &)': could not deduce template argument for 'const std::move_iterator<_RanIt> &' from 'const NodeTableIterator...'
Simple inspection inside std::copy
shows this source of error:
const auto _UDest = _Unchecked_n(_Dest, _Idl_distance<_InIt>(_UFirst, _ULast));
Where _Idl_distance really expects that my iterator should support operator -
.
Have you any idea how to overcome this strange requirement?
Upvotes: 3
Views: 97
Reputation: 20639
You need to provide the five types, either within the class itself:
template <class Container>
struct NodeTableIterator {
using iterator_category = /* ... */;
using value_type = /* ... */;
using difference_type = /* ... */;
using pointer = /* ... */;
using reference = /* ... */;
// ...
};
or within a custom specialization of std::iterator_traits
. Otherwise, the tag dispatch on the iterator category in the standard algorithms won't work.
Reference: [iterator.traits]/1 (the types in std::iterator_traits
are required to be present)
To implement algorithms only in terms of iterators, it is often necessary to determine the value and difference types that correspond to a particular iterator type. Accordingly, it is required that if
Iterator
is the type of an iterator, the typesiterator_traits<Iterator>::difference_type iterator_traits<Iterator>::value_type iterator_traits<Iterator>::iterator_category
be defined as the iterator's difference type, value type and iterator category, respectively. In addition, the types
iterator_traits<Iterator>::reference iterator_traits<Iterator>::pointer
shall be defined as the iterator's reference and pointer types, that is, for an iterator object
a
, the same type as the type of*a
anda->
, respectively. In the case of an output iterator, the typesiterator_traits<Iterator>::difference_type iterator_traits<Iterator>::value_type iterator_traits<Iterator>::reference iterator_traits<Iterator>::pointer
may be defined as
void
.
[iterator.traits]/2 (the types in std::iterator_traits
can be generated from the member types)
If
Iterator
has valid ([temp.deduct]) member typesdifference_type
,value_type
,pointer
,reference
, anditerator_category
,iterator_traits<Iterator>
shall have the following as publicly accessible members:using difference_type = typename Iterator::difference_type; using value_type = typename Iterator::value_type; using pointer = typename Iterator::pointer; using reference = typename Iterator::reference; using iterator_category = typename Iterator::iterator_category;
Otherwise,
iterator_traits<Iterator>
shall have no members by any of the above names.
Upvotes: 6
Reputation: 238431
You'll need to define NodeTableIterator::iterator_category
. More specifically, it must not be std::random_access_iterator_tag
or else operator-
will be required by the algorithm.
You also need to define
NodeTableIterator::difference_type
NodeTableIterator::value_type
NodeTableIterator::pointer
NodeTableIterator::reference
Or else std::iterator_traits
won't have any of those definitions. Or you can spesialise std::iterator_traits
explicitly. Note that if you don't do either of these things, then NodeTableIterator
is not an Iterator
at all.
Upvotes: 3