Getting std::iterator_category from boost iterator adaptor
I have a situation where I want to specialize a class template on the basis of iterator_category, but I don't see how to get one of the standard categories when passed a boost iterator adapter. Currently, std::iterator_traits<MyIter>::iterator_category is giving me: boost::iterator_tag<boost::writable_lvalue_iterator_tag , boost::random_access_traversal_tag> I need random_access_iterator_tag for the right specialization to happen. Is there any way to get the *standard* iterator category from a boost iterator? MyIter is boost::indirect_iterator<std::vector<int *>::iterator> compiler is gcc 3.2.3 (mingw special 20030504-1) BTW, isn't this non-standard iterator_category bound to cause problems? e.g. if I use std::distance (MyIter(), MyIter()), how does the compiler know that it should use the std::random_access_iterator_tag specialization of std::distance? -- Raoul Gough "Let there be one measure for wine throughout our kingdom, and one measure for ale, and one measure for corn" - Magna Carta
Raoul Gough <yg-boost-users@m.gmane.org> writes:
I have a situation where I want to specialize a class template on the basis of iterator_category, but I don't see how to get one of the standard categories when passed a boost iterator adapter. Currently, std::iterator_traits<MyIter>::iterator_category is giving me:
boost::iterator_tag<boost::writable_lvalue_iterator_tag , boost::random_access_traversal_tag>
I need random_access_iterator_tag for the right specialization to happen. Is there any way to get the *standard* iterator category from a boost iterator?
MyIter is boost::indirect_iterator<std::vector<int *>::iterator> compiler is gcc 3.2.3 (mingw special 20030504-1)
BTW, isn't this non-standard iterator_category bound to cause problems? e.g. if I use std::distance (MyIter(), MyIter()), how does the compiler know that it should use the std::random_access_iterator_tag specialization of std::distance?
Does your standard library really have a *specialization*? Most libraries use tag dispatching to discriminate categories - it works nicely with the inheritance structure of existing categories. Technically, you are right - a standard library is allowed to use specialization. AFAIK, none of them do, and we hope that when (if) our proposal is accepted, tag convertibility will be an acceptable standards-compliant mechanism. So, while I suggest you avoid specialization and use tag dispatching instead, if you must do it: // True iff T is a tag "derived" from Tag template <class Tag, class T> struct is_tag : mpl::or_< is_convertible<T, Tag> // Because we can't actually get forward_iterator_tag to // derive from input_output_iterator_tag, we need this // case. , mpl::and_< is_convertible<T,std::forward_iterator_tag> , is_convertible<detail::input_output_iterator_tag,Tag> > > {}; // Helper metafunction for std_category below template <class Cat, class Tag, class Next> struct match_tag : mpl::apply_if<is_tag<Tag, Cat>, mpl::identity<Tag>, Next> { }; // Converts a possibly user-defined category tag to the // most-derived standard tag which is a base of that tag. template <class Category> struct std_category : match_tag< Category, std::random_access_iterator_tag , match_tag<Category, std::bidirectional_iterator_tag , match_tag<Category, std::forward_iterator_tag , match_tag<Category, std::input_iterator_tag , match_tag<Category, std::output_iterator_tag # if BOOST_WORKAROUND(BOOST_MSVC, <= 1300) , mpl::identity<void> # else , void # endif > > > > > { }; Oops, I just lifted this code from boost/iterator/iterator_categories.hpp but it's in boost::detail::, so let your conscience be your guide... ;-> -- Dave Abrahams Boost Consulting www.boost-consulting.com
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes:
I have a situation where I want to specialize a class template on the basis of iterator_category, but I don't see how to get one of the standard categories when passed a boost iterator adapter. [snip] BTW, isn't this non-standard iterator_category bound to cause problems? e.g. if I use std::distance (MyIter(), MyIter()), how does the compiler know that it should use the std::random_access_iterator_tag specialization of std::distance?
Does your standard library really have a *specialization*? Most libraries use tag dispatching to discriminate categories - it works nicely with the inheritance structure of existing categories.
Aha - I had even tested std::distance, but couldn't figure out how it knew that the boost category matched random_access_iterator_tag. For some reason, I didn't realise that it was using function overloading rather than specialization. Of course, a specialization wouldn't make any sense in this case. On the other hand, I actually do need a specialization for the python range class extensions (which is where the original problem arose)...
Technically, you are right - a standard library is allowed to use specialization. AFAIK, none of them do, and we hope that when (if) our proposal is accepted, tag convertibility will be an acceptable standards-compliant mechanism. So, while I suggest you avoid specialization and use tag dispatching instead, if you must do it:
[snip hairy MPL code]
Oops, I just lifted this code from boost/iterator/iterator_categories.hpp but it's in boost::detail::, so let your conscience be your guide... ;->
OK, I've written something slightly simpler using is_convertible, since I really only need to cover two cases - a forward iterator or better (I'm using is_convertible<Category, std::forward_iterator_tag>) and random_access_iterator_tag or better. I'm using mpl::if to select between base classes for iterator_range. Thanks for putting me back on the right track - I'd forgotton about the whole iterator_category inheritance hierarchy (now revised from Josuttis's /Tutorial and Reference/ :-) -- Raoul Gough "Let there be one measure for wine throughout our kingdom, and one measure for ale, and one measure for corn" - Magna Carta
participants (2)
-
David Abrahams
-
Raoul Gough