Re: [Boost-users] [mpl] Iterator Concept Checking? SOLVED + Recommendation.
On Sun, Oct 31, 2010 at 6:16 PM, Stirling Westrup
On Sat, Oct 30, 2010 at 8:57 PM, David Abrahams
wrote: At Sat, 30 Oct 2010 17:55:35 -0400, Stirling Westrup wrote:
I am writing some algorithms to operate on MPL sequences, and I would like to use some form of concept checking to ensure that the types passed in that are supposed to be iterators are, in fact, iterators.
I have solved the problem I was working on, but as I'm not completely
happy with my solution, I thought I'd post it here and make a
recommendation for a small change to MPL that would have simplified my
work.
I discovered while reading about the iterator_category metafunction
that the iterator tags had ascending values. (
http://www.boost.org/doc/libs/1_44_0/libs/mpl/doc/refmanual/iterator-categor...
). This is only documented there, and not in the description of the
individual iterator categories. In fact, the individual iterator
categories are completely misleading as they state that there is a
member named 'category' that is convertible to the type of the tag.
Since a random iterator is a refinement of a forward iterator and
therefor has at least the same set of requirements, it would imply
that:
BOOST_MPL_ASSERT
(( is_convertibleRandomIterator::category,forward_iterator_tag))
should succeed, and it does NOT.
It would seem that one should use iterator_category to determine if
something is an iterator or not, but its only actually defined when
its type is an iterator, so that doesn't really work. I ended up
writing my own version that was defined for all types, like this:
struct non_iterator_tag : mpl::int_
At Tue, 2 Nov 2010 21:06:25 -0400, Stirling Westrup wrote:
On Sun, Oct 31, 2010 at 6:16 PM, Stirling Westrup
wrote: On Sat, Oct 30, 2010 at 8:57 PM, David Abrahams
wrote: At Sat, 30 Oct 2010 17:55:35 -0400, Stirling Westrup wrote:
I am writing some algorithms to operate on MPL sequences, and I would like to use some form of concept checking to ensure that the types passed in that are supposed to be iterators are, in fact, iterators.
I have solved the problem I was working on, but as I'm not completely happy with my solution, I thought I'd post it here and make a recommendation for a small change to MPL that would have simplified my work.
I discovered while reading about the iterator_category metafunction that the iterator tags had ascending values. ( http://www.boost.org/doc/libs/1_44_0/libs/mpl/doc/refmanual/iterator-categor... ). This is only documented there, and not in the description of the individual iterator categories. In fact, the individual iterator categories are completely misleading as they state that there is a
^^^^^^^^^^
member named 'category' that is convertible to the type of the tag.
Who states? Where? Oh, after searching... you mean, e.g., http://www.boost.org/doc/libs/1_44_0/libs/mpl/doc/refmanual/bidirectional-it... right?
Since a random iterator is a refinement of a forward iterator and therefor has at least the same set of requirements, it would imply that:
BOOST_MPL_ASSERT (( is_convertibleRandomIterator::category,forward_iterator_tag))
should succeed, and it does NOT.
What implies that? OK, found it...
It would seem that one should use iterator_category to determine if something is an iterator or not,
That wouldn't work for STL iterators; can you explain why you would expect it to work here?
but its only actually defined when its type is an iterator, so that doesn't really work. I ended up writing my own version that was defined for all types, like this:
struct non_iterator_tag : mpl::int_
{ typedef non_iterator_tag type; }; BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_category,category,false)
template
struct category_impl { typedef non_iterator_tag type; static const type::value_type value = type::value; }; template<typename T> struct category_impl
{ typedef typename mpl::iterator_category<T>::type type; static const int value = type::value; }; // just like mpl::iterator_category<T> but can be passed any // type, and returns mplx::not_iterator_tag on bad types. Note // that this value will compare less-than any valid iterator // tag. template<typename T> struct category : category_impl
{}; template<typename Iterator> struct is_forward_iterator { typedef typename mpl::greater_equal < typename category<Iterator>::type , mpl::forward_iterator_tag >::type type; };
template<typename Iterator> struct is_bidirectional_iterator { typedef typename mpl::greater_equal < typename category<Iterator>::type , mpl::bidirectional_iterator_tag >::type type; };
template<typename Iterator> struct is_random_access_iterator { typedef typename mpl::greater_equal < typename category<Iterator>::type , mpl::random_access_iterator_tag >::type type; };
The above works, but it relies upon me testing to see if there is an embedded category member, which I suspect is going to get deprecated by iterator_category<> just like all the other members were.
I'm sorry, I don't understand what you're trying to say about deprecation. Deprecation is a human activity; iterator_category<> can't deprecate anything.
It would be far preferable for me if there was an actual non_iterator_tag and iterator_category<> were already defined for all types, so it could both be used in a convenient manner, and so that there was an obvious way to write a specialization in the case that, for instance, one needed the type 'int' to be an iterator.
In the very least, please update the documentation to mention the actual relationships between the tags in the discussion about the iterators, and to remove the incorrect 'convertible' description.
Well, we have a problem, in that a BidirectionalIterator is-not-a ForwardIterator by MPL's requirements, even though the documentation claims it is a refinement. So MPL's concepts are just broken, and we need to fix that. Aleksey? -- Dave Abrahams BoostPro Computing http://www.boostpro.com
On Wed, Nov 3, 2010 at 10:02 PM, David Abrahams
At Tue, 2 Nov 2010 21:06:25 -0400, Stirling Westrup wrote:
I have solved the problem I was working on, but as I'm not completely happy with my solution, I thought I'd post it here and make a recommendation for a small change to MPL that would have simplified my work.
In fact, the individual iterator categories are completely misleading as they state that there is a ^^^^^^^^^^ member named 'category' that is convertible to the type of the tag.
Who states? Where? Oh, after searching... you mean, e.g., http://www.boost.org/doc/libs/1_44_0/libs/mpl/doc/refmanual/bidirectional-it... right?
Correct.
It would seem that one should use iterator_category to determine if something is an iterator or not,
That wouldn't work for STL iterators; can you explain why you would expect it to work here?
Well, as in the code I included in the original post of this thread, one usually wants to see what iterator concept is being modeled by a particular type, to ensure that the code that makes use of the type can rely on certain properties. Checking to see that something is an iterator and then checking to see if it is a particular model of an iterator seems to be a waste, as the only use of the first check is to see if the second would succeed. Why not just guarantee that the second would succeed? Its not hard to do, but it should be provided as part of the standard MPL, not as an add-on, as I did.
The above works, but it relies upon me testing to see if there is an embedded category member, which I suspect is going to get deprecated by iterator_category<> just like all the other members were.
I'm sorry, I don't understand what you're trying to say about deprecation. Deprecation is a human activity; iterator_category<> can't deprecate anything.
Sorry if I was unclear. I meant that use of Iterator::category would likely be deprecated in favour of using iterator_category<Iterator>::type, just as Iterator::deref and Iterator::next have been deprecated in favour of deref<Iterator>::type and next<Iterator>::type, and for the same reason. The extra level of indirection allows for greater flexibility in what sorts of types can be MPL iterators.
It would be far preferable for me if there was an actual non_iterator_tag and iterator_category<> were already defined for all types, so it could both be used in a convenient manner, and so that there was an obvious way to write a specialization in the case that, for instance, one needed the type 'int' to be an iterator.
I should mention, at this point, that this is completely analogous to how the sequence_tag<X> metafunction works, as it returns a valid sequence tag for any sequence type, and returns non_sequence_tag for any non-sequence. This is extremely useful, and I just want something that works exactly the same for iterators.
In the very least, please update the documentation to mention the actual relationships between the tags in the discussion about the iterators, and to remove the incorrect 'convertible' description.
Well, we have a problem, in that a BidirectionalIterator is-not-a ForwardIterator by MPL's requirements, even though the documentation claims it is a refinement. So MPL's concepts are just broken, and we need to fix that. Aleksey?
Yup. -- Stirling Westrup Programmer, Entrepreneur. https://www.linkedin.com/e/fpf/77228 http://www.linkedin.com/in/swestrup http://technaut.livejournal.com
On Tue, 02 Nov 2010 20:06:25 -0500, Stirling Westrup
On Sun, Oct 31, 2010 at 6:16 PM, Stirling Westrup
wrote: On Sat, Oct 30, 2010 at 8:57 PM, David Abrahams
wrote: At Sat, 30 Oct 2010 17:55:35 -0400, Stirling Westrup wrote:
I am writing some algorithms to operate on MPL sequences, and I would like to use some form of concept checking to ensure that the types passed in that are supposed to be iterators are, in fact, iterators.
I have solved the problem I was working on, but as I'm not completely happy with my solution, I thought I'd post it here and make a recommendation for a small change to MPL that would have simplified my work.
I discovered while reading about the iterator_category metafunction that the iterator tags had ascending values. ( http://www.boost.org/doc/libs/1_44_0/libs/mpl/doc/refmanual/iterator-categor... ). This is only documented there, and not in the description of the individual iterator categories. In fact, the individual iterator categories are completely misleading as they state that there is a member named 'category' that is convertible to the type of the tag. Since a random iterator is a refinement of a forward iterator and therefor has at least the same set of requirements, it would imply that:
BOOST_MPL_ASSERT (( is_convertibleRandomIterator::category,forward_iterator_tag))
should succeed, and it does NOT.
I agree, the docs are currently misleading/incorrect; please see below, though.
It would seem that one should use iterator_category to determine if something is an iterator or not, but its only actually defined when its type is an iterator, so that doesn't really work. I ended up writing my own version that was defined for all types, like this:
struct non_iterator_tag : mpl::int_
{ typedef non_iterator_tag type; }; BOOST_MPL_HAS_XXX_TRAIT_NAMED_DEF(has_category,category,false)
template
struct category_impl { typedef non_iterator_tag type; static const type::value_type value = type::value; }; template<typename T> struct category_impl
{ typedef typename mpl::iterator_category<T>::type type; static const int value = type::value; }; // just like mpl::iterator_category<T> but can be passed any // type, and returns mplx::not_iterator_tag on bad types. Note // that this value will compare less-than any valid iterator // tag. template<typename T> struct category : category_impl
{}; template<typename Iterator> struct is_forward_iterator { typedef typename mpl::greater_equal < typename category<Iterator>::type , mpl::forward_iterator_tag >::type type; };
template<typename Iterator> struct is_bidirectional_iterator { typedef typename mpl::greater_equal < typename category<Iterator>::type , mpl::bidirectional_iterator_tag >::type type; };
template<typename Iterator> struct is_random_access_iterator { typedef typename mpl::greater_equal < typename category<Iterator>::type , mpl::random_access_iterator_tag >::type type; };
The above works, but it relies upon me testing to see if there is an embedded category member, which I suspect is going to get deprecated by iterator_category<> just like all the other members were. It would be far preferable for me if there was an actual non_iterator_tag and iterator_category<> were already defined for all types, so it could both be used in a convenient manner, and so that there was an obvious way to write a specialization in the case that, for instance, one needed the type 'int' to be an iterator.
I considered this at some point, but in the end failed to come up with a use case for an iterator type that _has_ to be adopted "as is" and decided not to bother. Plus checking for the 'category' member is a little to broad of a test, IMHO.
In the very least, please update the documentation to mention the actual relationships between the tags in the discussion about the iterators, and to remove the incorrect 'convertible' description.
We can either fix the docs or fix the code. I'm actually inclined to fix the code. There are two reasons why I deviated from the standard iterator tags' relationship: 1. I wanted this to work: typedef typename min< typename iterator_category<iter1>::type , typename iterator_category<iter2>::type >::type category; 2. I *thought* I had no use case for keeping the inheritance, and preserving it while also supporting #1 seemed like unnecessary hassle. Now that you pointed out that by removing it I both broke the docs *and* violated at least one person's expectations, "the hassle" seems more like a win-win solution to me: the docs would become correct again, you (and the rest of the users) would get intuitively expected, standard-like relationship between tags and ability to test them with 'is_convertible', and I'd still get to keep #1. Thoughts? -- Aleksey Gurtovoy MetaCommunications Engineering
participants (3)
-
Aleksey Gurtovoy
-
David Abrahams
-
Stirling Westrup