Implementing python's enumerate with iterator adaptors

Hi, I am implementing something similar to python's enumerate using boost iterator adapter, but I am running into two problems I am unable to solve. Both problems use my Enumerate-adaptor defined as: #include <utility> #include <boost/iterator/iterator_adaptor.hpp> namespace Iterator { // some simple wrapper to have better names than std::pair template<typename T, typename X> struct Enumerated { Enumerated(T i, X x): count(i), value(x) { } T count; X value; }; template< typename Iterator, typename T = typename Iterator::difference_type> class Enumerator: public boost::iterator_adaptor<Enumerator<Iterator, T>, Iterator, Enumerated<T, typename Iterator::value_type>, boost::use_default, Enumerated<T, typename Iterator::reference> > { public: Enumerator(): mCount(), mPos(), mStep() { } template<typename It> explicit Enumerator(It i, T start=T(), T step=T(1) ): mCount(start), mPos(i), mStep(step) { } private: friend class boost::iterator_core_access; Enumerated<T, typename Iterator::reference > dereference() const { return Enumerated<T, typename Iterator::reference >(mCount, *mPos); } Enumerated<T, typename Iterator::reference > dereference() { return Enumerated<T, typename Iterator::reference >(mCount, mPos); } bool equal(Enumerator<Iterator, T> const& other) const { return mPos == mPos; } void increment() { mCount += mStep; mPos += 1; } void decrement() { mCount -= mStep; mPos -= 1; } void advance(typename Iterator::difference_type step) { mCount += step * mStep; mPos += step; } typename Iterator::difference_type distance_to(Enumerator<Iterator, T> const& other) const { return std::distance(mPos, other.mPos); } T mCount; Iterator mPos; typename Iterator::difference_type mStep; }; template<typename Iterator, typename T> Enumerator<Iterator, T> enumerate(Iterator i, T start=0, T step=1) { return Enumerator<Iterator, T>(i, start, step); } When I compile the following sample program, msvc (VS2010) prints an error, but g++ does not have any problems. #include <vector> #include <iostream> #include <algorithm> void foo() { std::vector<int> v; auto i = Iterator::enumerate(v.begin(), 0, 1); auto j = Iterator::enumerate(v.end(), 0, 1); std::for_each( i, j, [](decltype(*i) e) { std::cout << e.count << ", " << e.value << std::endl; }); } Error 1 error C2665: 'std::_Debug_range2' : none of the 2 overloads could convert all the argument types d:\programme\microsoft visual studio 10.0\vc\include\xutility 728 My second problem can be reproduced with the following sample program on both msvc and g++: #include <vector> #include <iostream> #include <algorithm> void foo() { std::vector<int> v; auto i = Iterator::enumerate(v.begin(), 0, 1); auto y = i->count; auto z = i->value; } MSVC: Error 3 error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'Iterator::Enumerated<T,X> *' to 'boost::detail::operator_arrow_proxy<T>' c:\software development\externals\include\boost\iterator\iterator_facade.hpp 326 G++: In file included from /usr/include/boost/iterator/iterator_adaptor.hpp:15:0, from Enumerate.h:18, from Enumerate.cpp:1: /usr/include/boost/iterator/iterator_facade.hpp: In static member function 'static boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::type boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::make(Reference) [with ValueType = Iterator::Enumerated<int, int>, Reference = Iterator::Enumerated<int, int&>, Pointer = Iterator::Enumerated<int, int>*, boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::type = boost::detail::operator_arrow_proxy<Iterator::Enumerated<int, int> >]': /usr/include/boost/iterator/iterator_facade.hpp:648:49: instantiated from 'boost::iterator_facade<I, V, TC, R, D>::pointer boost::iterator_facade<I, V, TC, R, D>::operator->() const [with Derived = Iterator::Enumerator<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, int>, Value = Iterator::Enumerated<int, int>, CategoryOrTraversal = boost::random_access_traversal_tag, Reference = Iterator::Enumerated<int, int&>, Difference = int, boost::iterator_facade<I, V, TC, R, D>::pointer = boost::detail::operator_arrow_proxy<Iterator::Enumerated<int, int> >]' Enumerate.cpp:27:14: instantiated from here /usr/include/boost/iterator/iterator_facade.hpp:327:49: error: no matching function for call to 'implicit_cast(Iterator::Enumerated<int, int&>*)' Any help would be greatly appreciated, Bets regards, Jens

On 17 April 2012 13:03, Jens Auer <jensa@miltenyibiotec.de> wrote:
bool equal(Enumerator<Iterator, T> const& other) const
{
return mPos == mPos;
}
You likely have a bug above, should read other.mPos.
My second problem can be reproduced with the following sample program on both msvc and g++:
#include <vector>
#include <iostream>
#include <algorithm>
void foo()
{
std::vector<int> v;
auto i = Iterator::enumerate(v.begin(), 0, 1);
auto y = i->count;
auto z = i->value;
}
MSVC:
Error 3 error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'Iterator::Enumerated<T,X> *' to 'boost::detail::operator_arrow_proxy<T>' c:\software development\externals\include\boost\iterator\iterator_facade.hpp 326
G++:
In file included from /usr/include/boost/iterator/iterator_adaptor.hpp:15:0,
from Enumerate.h:18,
from Enumerate.cpp:1:
/usr/include/boost/iterator/iterator_facade.hpp: In static member function 'static boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::type boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::make(Reference) [with ValueType = Iterator::Enumerated<int, int>, Reference = Iterator::Enumerated<int, int&>, Pointer = Iterator::Enumerated<int, int>*, boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::type = boost::detail::operator_arrow_proxy<Iterator::Enumerated<int, int> >]':
/usr/include/boost/iterator/iterator_facade.hpp:648:49: instantiated from 'boost::iterator_facade<I, V, TC, R, D>::pointer boost::iterator_facade<I, V, TC, R, D>::operator->() const [with Derived = Iterator::Enumerator<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, int>, Value = Iterator::Enumerated<int, int>, CategoryOrTraversal = boost::random_access_traversal_tag, Reference = Iterator::Enumerated<int, int&>, Difference = int, boost::iterator_facade<I, V, TC, R, D>::pointer = boost::detail::operator_arrow_proxy<Iterator::Enumerated<int, int> >]'
Enumerate.cpp:27:14: instantiated from here
/usr/include/boost/iterator/iterator_facade.hpp:327:49: error: no matching function for call to 'implicit_cast(Iterator::Enumerated<int, int&>*)'
It seems you haven't specified what version of Boost you are using. I suppose you are hitting bug fixed a few months ago. Try with Boost trunk and the second program should compile. I haven't checked the first use case issue though. (FYI, There is no need to post in HTML to public mailing lists. If it wasn't in HTML, your code above would have been well formatted.) Best regards, -- Mateusz Loskot, http://mateusz.loskot.net

Thanks for pointing at the bug. Can you give me the bug number so I can check if it is solved in boost version I am using? I used boost 1.48 with g++ and 1.46 with msvc. And sorry for the html mail, I normally have Outlook configured to not send html but standard txt, I don't why this was active. If anybody is interested, here is the source code as text. I have also corrected the bug in equal(). #include <utility> #include <boost/iterator/iterator_adaptor.hpp> namespace Iterator { template<typename T, typename X> struct Enumerated { Enumerated(T i, X x): count(i), value(x) { } T count; X value; }; template< typename Iterator, typename T = typename Iterator::difference_type> class Enumerator: public boost::iterator_adaptor<Enumerator<Iterator, T>, Iterator, Enumerated<T, typename Iterator::value_type>, boost::use_default, Enumerated<T, typename Iterator::reference> > { public: Enumerator(): mCount(), mPos(), mStep() { } template<typename It> explicit Enumerator(It i, T start=T(), T step=T(1) ): mCount(start), mPos(i), mStep(step) { } private: friend class boost::iterator_core_access; Enumerated<T, typename Iterator::reference > dereference() const { return Enumerated<T, typename Iterator::reference >(mCount, *mPos); } Enumerated<T, typename Iterator::reference > dereference() { return Enumerated<T, typename Iterator::reference >(mCount, mPos); } bool equal(Enumerator<Iterator, T> const& other) const { return mPos == other.mPos; } void increment() { mCount += mStep; mPos += 1; } void decrement() { mCount -= mStep; mPos -= 1; } void advance(typename Iterator::difference_type step) { mCount += step * mStep; mPos += step; } typename Iterator::difference_type distance_to(Enumerator<Iterator, T> const& other) const { return std::distance(mPos, other.mPos); } T mCount; Iterator mPos; typename Iterator::difference_type mStep; }; template<typename Iterator, typename T> Enumerator<Iterator, T> enumerate(Iterator i, T start=0, T step=1) { return Enumerator<Iterator, T>(i, start, step); } #include <vector> #include <iostream> #include <algorithm> void foo() { std::vector<int> v; auto i = Iterator::enumerate(v.begin(), 0, 1); auto j = Iterator::enumerate(v.end(), 0, 1); std::for_each(i, j, [](decltype(*i) const& x) { std::cout << x.count << ", " << x.value << std::endl; } ); auto y = i->count; auto z = i->value; } -----Ursprüngliche Nachricht----- Von: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] Im Auftrag von Mateusz Loskot Gesendet: Dienstag, 17. April 2012 15:21 An: boost-users@lists.boost.org Betreff: Re: [Boost-users] Implementing python's enumerate with iterator adaptors On 17 April 2012 13:03, Jens Auer <jensa@miltenyibiotec.de> wrote:
bool equal(Enumerator<Iterator, T> const& other) const
{
return mPos == mPos;
}
You likely have a bug above, should read other.mPos.
My second problem can be reproduced with the following sample program on both msvc and g++:
#include <vector>
#include <iostream>
#include <algorithm>
void foo()
{
std::vector<int> v;
auto i = Iterator::enumerate(v.begin(), 0, 1);
auto y = i->count;
auto z = i->value;
}
MSVC:
Error 3 error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'Iterator::Enumerated<T,X> *' to 'boost::detail::operator_arrow_proxy<T>' c:\software development\externals\include\boost\iterator\iterator_facade.hpp 326
G++:
In file included from /usr/include/boost/iterator/iterator_adaptor.hpp:15:0,
from Enumerate.h:18,
from Enumerate.cpp:1:
/usr/include/boost/iterator/iterator_facade.hpp: In static member function 'static boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::type boost::detail::operator_arrow_result<ValueType, Pointer>Reference, Pointer>::make(Reference) [with ValueType = Iterator::Enumerated<int, Pointer>int>, Reference = Iterator::Enumerated<int, int&>, Pointer = Iterator::Enumerated<int, int>*, boost::detail::operator_arrow_result<ValueType, Reference, Pointer>::type = boost::detail::operator_arrow_proxy<Iterator::Enumerated<int, int> >]':
/usr/include/boost/iterator/iterator_facade.hpp:648:49: instantiated from 'boost::iterator_facade<I, V, TC, R, D>::pointer boost::iterator_facade<I, V, TC, R, D>::operator->() const [with Derived = Iterator::Enumerator<__gnu_cxx::__normal_iterator<int*, std::vector<int> >, int>, Value = Iterator::Enumerated<int, int>, CategoryOrTraversal = boost::random_access_traversal_tag, Reference = Iterator::Enumerated<int, int&>, Difference = int, boost::iterator_facade<I, V, TC, R, D>::pointer = boost::detail::operator_arrow_proxy<Iterator::Enumerated<int, int> >]'
Enumerate.cpp:27:14: instantiated from here
/usr/include/boost/iterator/iterator_facade.hpp:327:49: error: no matching function for call to 'implicit_cast(Iterator::Enumerated<int, int&>*)'
It seems you haven't specified what version of Boost you are using. I suppose you are hitting bug fixed a few months ago. Try with Boost trunk and the second program should compile. I haven't checked the first use case issue though. (FYI, There is no need to post in HTML to public mailing lists. If it wasn't in HTML, your code above would have been well formatted.) Best regards, -- Mateusz Loskot, http://mateusz.loskot.net _______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On Tue, Apr 17, 2012 at 5:03 AM, Jens Auer <jensa@miltenyibiotec.de> wrote:
Hi,****
** **
I am implementing something similar to python’s enumerate using boost iterator adapter, but I am running into two problems I am unable to solve. Both problems use my Enumerate-adaptor defined as:****
#include <utility>****
** **
#include <boost/iterator/iterator_adaptor.hpp>****
** **
namespace Iterator****
{****
// some simple wrapper to have better names than std::pair****
template<typename T, typename X>****
struct Enumerated****
{****
Enumerated(T i, X x):****
count(i),****
value(x)****
{****
** **
}****
** **
T count;****
X value;****
};****
** **
template< typename Iterator, typename T = typenameIterator::difference_type>
****
class Enumerator:****
public boost::iterator_adaptor<Enumerator<Iterator, T>,****
Iterator,****
Enumerated<T, typenameIterator::value_type>, ****
boost::use_default,****
Enumerated<T, typenameIterator::reference> > ****
{****
public:****
Enumerator():****
mCount(),****
mPos(),****
mStep()****
{****
** **
}****
** **
template<typename It>****
explicit Enumerator(It i, T start=T(), T step=T(1) ):****
mCount(start),****
mPos(i),****
mStep(step)****
{****
** **
}****
** **
private:****
friend class boost::iterator_core_access;****
** **
Enumerated<T, typename Iterator::reference > dereference() const****
{****
return Enumerated<T, typename Iterator::reference >(mCount, *mPos);* ***
}****
** **
Enumerated<T, typename Iterator::reference > dereference()****
{****
return Enumerated<T, typename Iterator::reference >(mCount, mPos);** **
}
Pretty sure this latter overload of dereference will never get called, and it wouldn't compile anyway ("mPos" should be "*mPos"). ****
** **
bool equal(Enumerator<Iterator, T> const& other) const****
{****
return mPos == mPos;****
}
Error already noted here.
****
** **
void increment()****
{****
mCount += mStep;****
mPos += 1;****
}
Consider ++mPos?
****
** **
void decrement()****
{****
mCount -= mStep;****
mPos -= 1;****
}
Similarly, consider --mPos?
****
** **
void advance(typename Iterator::difference_type step)****
{****
mCount += step * mStep;****
mPos += step;****
}****
** **
typename Iterator::difference_type distance_to(Enumerator<Iterator, T> const& other) const****
{****
return std::distance(mPos, other.mPos);****
}****
** **
T mCount;****
Iterator mPos;****
typename Iterator::difference_type mStep;****
};****
** **
template<typename Iterator, typename T>****
Enumerator<Iterator, T> enumerate(Iterator i, T start=0, T step=1)****
{****
return Enumerator<Iterator, T>(i, start, step);****
}****
** **
When I compile the following sample program, msvc (VS2010) prints an error, but g++ does not have any problems.****
#include <vector>****
#include <iostream>****
#include <algorithm>****
** **
void foo()****
{****
std::vector<int> v;****
** **
auto i = Iterator::enumerate(v.begin(), 0, 1);****
auto j = Iterator::enumerate(v.end(), 0, 1);****
** **
std::for_each( i, j, [](decltype(*i) e)****
{****
std::cout << e.count << ", " << e.value << std::endl;****
});****
}****
Error 1 error C2665: 'std::_Debug_range2' : none of the 2 overloads could convert all the argument types d:\programme\microsoft visual studio 10.0\vc\include\xutility 728
Can you give more context to the error message?
****
My second problem can be reproduced with the following sample program on both msvc and g++:****
** **
#include <vector>****
#include <iostream>****
#include <algorithm>****
** **
void foo()****
{****
std::vector<int> v;****
** **
auto i = Iterator::enumerate(v.begin(), 0, 1);****
** **
auto y = i->count;****
auto z = i->value;****
}****
MSVC:****
Error 3 error C2664: 'boost::implicit_cast' : cannot convert parameter 1 from 'Iterator::Enumerated<T,X> *' to 'boost::detail::operator_arrow_proxy<T>' c:\software development\externals\include\boost\iterator\iterator_facade.hpp 326
As Mateusz has noted, I believe you're running into https://svn.boost.org/trac/boost/ticket/5697 which was just recently fixed in trunk. See if that resolves your problem. [snip compiler trace] - Jeff

Thanks for all the suggestions, they are highly welcome. The output of the MS compiler with the error message is: 1>d:\programme\microsoft visual studio 10.0\vc\include\xutility(728): error C2665: 'std::_Debug_range2' : none of the 2 overloads could convert all the argument types 1> d:\programme\microsoft visual studio 10.0\vc\include\xutility(703): could be 'void std::_Debug_range2<_InIt>(_InIt,_InIt,std::_Dbfile_t,std::_Dbline_t,std::input_iterator_tag)' 1> with 1> [ 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] 1> d:\programme\microsoft visual studio 10.0\vc\include\xutility(711): or 'void std::_Debug_range2<_InIt>(_RanIt,_RanIt,std::_Dbfile_t,std::_Dbline_t,std::random_access_iterator_tag)' 1> with 1> [ 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int>, 1> _RanIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] 1> while trying to match the argument list '(Iterator::Enumerator<Iterator,T>, Iterator::Enumerator<Iterator,T>, std::_Dbfile_t, std::_Dbline_t, boost::random_access_traversal_tag)' 1> with 1> [ 1> Iterator=std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>, 1> T=int 1> ] 1> d:\programme\microsoft visual studio 10.0\vc\include\algorithm(30) : see reference to function template instantiation 'void std::_Debug_range<_InIt>(_InIt,_InIt,std::_Dbfile_t,std::_Dbline_t)' being compiled 1> with 1> [ 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] 1> c:\software development\svn\swdev\cap\mblib\iterator\enumerate.cpp(27) : see reference to function template instantiation '_Fn1 std::for_each<Iterator::Enumerator<Iterator,T>,`anonymous-namespace'::`anonymous-namespace'::<lambda0>>(_InIt,_InIt,_Fn1)' being compiled 1> with 1> [ 1> _Fn1=`anonymous-namespace'::`anonymous-namespace'::<lambda0>, 1> Iterator=std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>, 1> T=int, 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] If anybody is interested I can create a small solution with a project file to reproduce it. Best regards, Jens

On Tue, Apr 17, 2012 at 8:04 AM, Jens Auer <jensa@miltenyibiotec.de> wrote:
Thanks for all the suggestions, they are highly welcome. The output of the MS compiler with the error message is: 1>d:\programme\microsoft visual studio 10.0\vc\include\xutility(728): error C2665: 'std::_Debug_range2' : none of the 2 overloads could convert all the argument types 1> d:\programme\microsoft visual studio 10.0\vc\include\xutility(703): could be 'void std::_Debug_range2<_InIt>(_InIt,_InIt,std::_Dbfile_t,std::_Dbline_t,std::input_iterator_tag)' 1> with 1> [ 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] 1> d:\programme\microsoft visual studio 10.0\vc\include\xutility(711): or 'void std::_Debug_range2<_InIt>(_RanIt,_RanIt,std::_Dbfile_t,std::_Dbline_t,std::random_access_iterator_tag)' 1> with 1> [ 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int>, 1> _RanIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] 1> while trying to match the argument list '(Iterator::Enumerator<Iterator,T>, Iterator::Enumerator<Iterator,T>, std::_Dbfile_t, std::_Dbline_t, boost::random_access_traversal_tag)' 1> with 1> [ 1> Iterator=std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>, 1> T=int 1> ] 1> d:\programme\microsoft visual studio 10.0\vc\include\algorithm(30) : see reference to function template instantiation 'void std::_Debug_range<_InIt>(_InIt,_InIt,std::_Dbfile_t,std::_Dbline_t)' being compiled 1> with 1> [ 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ] 1> c:\software development\svn\swdev\cap\mblib\iterator\enumerate.cpp(27) : see reference to function template instantiation '_Fn1 std::for_each<Iterator::Enumerator<Iterator,T>,`anonymous-namespace'::`anonymous-namespace'::<lambda0>>(_InIt,_InIt,_Fn1)' being compiled 1> with 1> [ 1> _Fn1=`anonymous-namespace'::`anonymous-namespace'::<lambda0>, 1> Iterator=std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>, 1> T=int, 1> _InIt=Iterator::Enumerator<std::_Vector_iterator<std::_Vector_val<int,std::allocator<int>>>,int> 1> ]
If anybody is interested I can create a small solution with a project file to reproduce it.
Looks like boost::random_access_traversal_tag doesn't have a "best conversion" among std::input_iterator_tag std::random_access_iterator_tag My guess is this is where that proxy reference bites you, as it makes your Enumerator iterator not strictly a random access iterator, even though it morally is, so boost::iterator_facade won't set your iterator_category to std::random_access_iterator_tag and instead tries to go a middle-of-the-road approach (IIRC). Try typedef'ing typedef std::random_access_iterator_tag iterator_category; // I think this is right... in your Enumerator definition and see if MSVC complains? - Jeff

Von: boost-users-bounces@lists.boost.org [mailto:boost-users-bounces@lists.boost.org] Im Auftrag von Jeffrey Lee Hellrung, Jr. 1> My guess is this is where that proxy reference bites you, as it makes your Enumerator iterator not strictly a random access iterator, even though it morally is, so boost::iterator_facade won't set your 1> iterator_category to std::random_access_iterator_tag and instead tries to go a middle-of-the-road approach (IIRC). Try typedef'ing 1> 1> typedef std::random_access_iterator_tag iterator_category; // I think this is right... 1> 1> in your Enumerator definition and see if MSVC complains? Hi Jeff, this fixed the problem and now it compiles, although I would prefer typedef typename Iterator::iterator_category iterator_category; to make the Enumerator the same category as the underlying iterator. Thanks, Jens

On Wed, Apr 18, 2012 at 12:11 AM, Jens Auer <jensa@miltenyibiotec.de> wrote:
Von: boost-users-bounces@lists.boost.org [mailto: boost-users-bounces@lists.boost.org] Im Auftrag von Jeffrey Lee Hellrung, Jr. 1> My guess is this is where that proxy reference bites you, as it makes your Enumerator iterator not strictly a random access iterator, even though it morally is, so boost::iterator_facade won't set your 1> iterator_category to std::random_access_iterator_tag and instead tries to go a middle-of-the-road approach (IIRC). Try typedef'ing 1> 1> typedef std::random_access_iterator_tag iterator_category; // I think this is right... 1> 1> in your Enumerator definition and see if MSVC complains?
Hi Jeff,
this fixed the problem and now it compiles, although I would prefer typedef typename Iterator::iterator_category iterator_category;
to make the Enumerator the same category as the underlying iterator.
Yes, you are correct, that would be more general (actually, you would use std::iterator_traits< Iterator >::iterator_category rather than Iterator::iterator_category, to be precise). It's just if you grab the iterator_category from boost::iterator_adaptor, you'll lose strict random access due to the reference type being a proxy. Indeed, the most robust solution for your use case would probably be to use some metaprogramming logic to determine the iterator_category similar to that outlined in boost::iterator_facade, but which doesn't see a proxy reference as immediately knocking down the iterator_category to std::input_iterator_tag or whatever. So, in C++03, you'd technically be lying to your standard library implementation if you say your iterator_category is random access but you have proxy references, since *i is suppose to a "real" reference. However, my draft of the C++11 standard seems to have dropped this requirement, indicating that you're safe, at least on standard library implementations that follow the C++11 iterator requirements as opposed to the C++03 iterator requirements (and I don't know where the version of MSVC you're using stands in this regard). In any case, I think I'll raise this issue on the developers' list... - Jeff
participants (3)
-
Jeffrey Lee Hellrung, Jr.
-
Jens Auer
-
Mateusz Loskot