indirect_iterator_generator<list<shared_ptr<X> >::iterator> again

Using gcc 3.2 (on MinGW) the template parameter defaults for indirect_iterator_generator don't work with shared_ptr. This has been discussed* on the list before, but there doesn't seem to have been a user-friendly resolution to the issues involved (at least not in release 1_30_0). Using my compiler, the current situation requires the client code to supply all five of the template parameters. *some previous threads on the subject: http://groups.yahoo.com/group/Boost-Users/message/1618 http://lists.boost.org/MailArchives/boost/msg33273.php http://lists.boost.org/MailArchives/boost/msg33316.php My sample code: #include <boost/iterator_adaptors.hpp> #include <boost/shared_ptr.hpp> #include <list> int main () { typedef std::list<boost::shared_ptr<int> > ListType; typedef ListType::iterator BaseIterator; typedef boost::indirect_iterator_generator<BaseIterator>::type Adapter; } Error output: f:/mingw/include/c++/3.2/bits/stl_iterator_base_types.h: In instantiation of `std::iterator_traits<boost::shared_ptr<int> >': d:/CVS/boost/boost/boost/iterator_adaptors.hpp:1111: instantiated from `boost::detail::iterator_traits<boost::shared_ptr<int> >' d:/CVS/boost/boost/boost/iterator_adaptors.hpp:1111: instantiated from `boost::detail::traits_of_value_type<main()::BaseIterator>' iterator_adapter.cc:9: instantiated from here f:/mingw/include/c++/3.2/bits/stl_iterator_base_types.h:123: no type named ` iterator_category' in `class boost::shared_ptr<int>' f:/mingw/include/c++/3.2/bits/stl_iterator_base_types.h:125: no type named ` difference_type' in `class boost::shared_ptr<int>' Looking at iterator_adaptors.hpp:1111 we have (reformatted): struct traits_of_value_type { typedef typename boost::detail::iterator_traits<T>::value_type outer_value; typedef typename boost::detail::iterator_traits<outer_value>::value_type value_type; typedef typename boost::detail::iterator_traits<outer_value>::reference reference; typedef typename boost::detail::iterator_traits<outer_value>::pointer pointer; }; So traits_of_value_type tries to look up the *iterator_traits* of the *value type* for the supplied iterator. Does the value type really need to have complete iterator traits for the compiler to figure out the defaults here? Is anybody working on improving the ease-of-use for indirect_iterator_generator? -- 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:
Using gcc 3.2 (on MinGW) the template parameter defaults for indirect_iterator_generator don't work with shared_ptr. This has been discussed* on the list before, but there doesn't seem to have been a user-friendly resolution to the issues involved (at least not in release 1_30_0).
Right. The user-friendly solution is to use the iterator adaptors in the current Boost CVS. There won't be a fix for 1.30.0.
Looking at iterator_adaptors.hpp:1111 we have (reformatted):
struct traits_of_value_type { typedef typename boost::detail::iterator_traits<T>::value_type outer_value; typedef typename boost::detail::iterator_traits<outer_value>::value_type value_type; typedef typename boost::detail::iterator_traits<outer_value>::reference reference; typedef typename boost::detail::iterator_traits<outer_value>::pointer pointer; };
So traits_of_value_type tries to look up the *iterator_traits* of the *value type* for the supplied iterator. Does the value type really need to have complete iterator traits for the compiler to figure out the defaults here? Is anybody working on improving the ease-of-use for indirect_iterator_generator?
Nope. You could always specialize traits_of_value_type to make it work for your case. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes:
Using gcc 3.2 (on MinGW) the template parameter defaults for indirect_iterator_generator don't work with shared_ptr. This has been discussed* on the list before, but there doesn't seem to have been a user-friendly resolution to the issues involved (at least not in release 1_30_0).
Right. The user-friendly solution is to use the iterator adaptors in the current Boost CVS. There won't be a fix for 1.30.0.
Hi Dave, Thanks very much for your reply. I've switched to the CVS head, and can get my test case to compile as follows: #include <boost/iterator/indirect_iterator.hpp> #include <boost/shared_ptr.hpp> #include <list> int main () { typedef std::list<boost::shared_ptr<int> > ListType; typedef ListType::iterator BaseIterator; typedef boost::indirect_iterator<BaseIterator> Adapter; } Is that about right? It looks like the main documentation isn't up to date yet, since it links to libs/utility/indirect_iterator.htm which still talks about indirect_iterator_generator. On a different note, /libs/iterator/doc/facade-and-adaptor.html says: If the default is used for Value, then there must be a valid specialization of iterator_traits for the value type of the base iterator. Is a full iterator_traits actually necessary? Just seems to me that there is conceptual difference between (let's say) dereferencable_traits (which any proxy type could have) and a full-blown iterator_traits (which smart pointers probably wouldn't have). -- 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:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes:
Using gcc 3.2 (on MinGW) the template parameter defaults for indirect_iterator_generator don't work with shared_ptr. This has been discussed* on the list before, but there doesn't seem to have been a user-friendly resolution to the issues involved (at least not in release 1_30_0).
Right. The user-friendly solution is to use the iterator adaptors in the current Boost CVS. There won't be a fix for 1.30.0.
Hi Dave,
Thanks very much for your reply. I've switched to the CVS head, and can get my test case to compile as follows:
#include <boost/iterator/indirect_iterator.hpp> #include <boost/shared_ptr.hpp> #include <list>
int main () { typedef std::list<boost::shared_ptr<int> > ListType; typedef ListType::iterator BaseIterator; typedef boost::indirect_iterator<BaseIterator> Adapter; }
Is that about right?
Yep.
It looks like the main documentation isn't up to date yet, since it links to libs/utility/indirect_iterator.htm which still talks about indirect_iterator_generator.
Right.
On a different note, /libs/iterator/doc/facade-and-adaptor.html says:
If the default is used for Value, then there must be a valid specialization of iterator_traits for the value type of the base iterator.
That's not quite accurate. The actual rule is: if the value_type of the Base iterator is a class with a nested ::element_type, remove_const< iterator_traits<Base>::value_type::element_type
::type
will be the value type of the resulting iterator. Otherwise, there must be a valid iterator_traits specialization of iterator_traits for the value type of the base iterator. We probably ought to define a public referent<T> metafunction in namespace boost which implements that logic, so that people can specialize it.
Is a full iterator_traits actually necessary? Just seems to me that there is conceptual difference between (let's say) dereferencable_traits (which any proxy type could have) and a full-blown iterator_traits (which smart pointers probably wouldn't have).
Right. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
We probably ought to define a public referent<T> metafunction in namespace boost which implements that logic, so that people can specialize it.
That's done; the docs still need to be updated to reflect that fact though. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
David Abrahams <dave@boost-consulting.com> writes:
We probably ought to define a public referent<T> metafunction in namespace boost which implements that logic, so that people can specialize it.
That's done; the docs still need to be updated to reflect that fact though.
Alright! So I can now specialize boost::referent for my own smart pointer template: namespace boost { template<class T> struct referent<utils::weak_ptr<T> > { typedef T type; }; } Really seems a bit weird that boost::referent wasn't already invented in the type_traits portion of the library, since it can be applied to any kind of pointer, iterator, etc... Anyway, it has neatened up my code quite a bit, thanks. -- 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:
David Abrahams <dave@boost-consulting.com> writes:
David Abrahams <dave@boost-consulting.com> writes:
We probably ought to define a public referent<T> metafunction in namespace boost which implements that logic, so that people can specialize it.
That's done; the docs still need to be updated to reflect that fact though.
Alright! So I can now specialize boost::referent for my own smart pointer template:
namespace boost { template<class T> struct referent<utils::weak_ptr<T> > { typedef T type; }; }
If neccessary. It usually isn't, though.
Really seems a bit weird that boost::referent wasn't already invented in the type_traits portion of the library, since it can be applied to any kind of pointer, iterator, etc... Anyway, it has neatened up my code quite a bit, thanks.
It's a little quirky, yet. If you define an iterator with a nested element_type member it will do the wrong thing. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes: [snip]
Really seems a bit weird that boost::referent wasn't already invented in the type_traits portion of the library, since it can be applied to any kind of pointer, iterator, etc... Anyway, it has neatened up my code quite a bit, thanks.
It's a little quirky, yet. If you define an iterator with a nested element_type member it will do the wrong thing.
I guess in an ideal world, we would have something like this: template<typename T> struct handle_traits { typedef typename T::value_type value_type; typedef typename T::pointer_type pointer_type; typedef typename T::reference_type reference_type; }; template<typename T> struct iterator_traits : public handle_traits<T> { typedef typename T::iterator_category iterator_category; typedef typename T::difference_type difference_type; }; Since an iterator is-a handle with additional functionality (i.e. movability to one extent or another). In the case of indirect_iterator<T>, we would need valid instantiations for iterator_traits<T> and handle_traits<iterator_traits<T>::value_type> BTW, does it ever make sense to have pointer_type != (value_type *) or reference_type != (value_type &) ?? -- 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:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes: [snip]
Really seems a bit weird that boost::referent wasn't already invented in the type_traits portion of the library, since it can be applied to any kind of pointer, iterator, etc... Anyway, it has neatened up my code quite a bit, thanks.
It's a little quirky, yet. If you define an iterator with a nested element_type member it will do the wrong thing.
I guess in an ideal world, we would have something like this:
template<typename T> struct handle_traits { typedef typename T::value_type value_type; typedef typename T::pointer_type pointer_type; typedef typename T::reference_type reference_type; };
template<typename T> struct iterator_traits : public handle_traits<T> { typedef typename T::iterator_category iterator_category; typedef typename T::difference_type difference_type; };
I don't see why that's preferable to what we have now with referent.
Since an iterator is-a handle with additional functionality (i.e. movability to one extent or another). In the case of indirect_iterator<T>, we would need valid instantiations for iterator_traits<T> and handle_traits<iterator_traits<T>::value_type>
BTW, does it ever make sense to have pointer_type != (value_type *) or reference_type != (value_type &) ??
Yes to the latter; you can read all about it in the new iterator adaptor / facade / concepts documents. Also see std::vector<bool>::iterator. -- Dave Abrahams Boost Consulting www.boost-consulting.com

David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes: [snip]
I guess in an ideal world, we would have something like this:
template<typename T> struct handle_traits { typedef typename T::value_type value_type; typedef typename T::pointer_type pointer_type; typedef typename T::reference_type reference_type; };
template<typename T> struct iterator_traits : public handle_traits<T> { typedef typename T::iterator_category iterator_category; typedef typename T::difference_type difference_type; };
I don't see why that's preferable to what we have now with referent.
After realising that an iterator is just a kind of handle that supports movement (according to its iterator_category) I figured that the traits subclassing was an accurate representation. Doing it this way, with handle_traits more general than iterator_traits (and at least as visible to client code) it seems like a good central repository for the type information. If you only want info about operator*() then you can use handle_traits<T> without knowing whether T is really an iterator. It also helps to document the requirements. For example, a valid handle class T requires handle_traits<T> and an operator*() that returns handle_traits<T>::reference_type. A valid iterator T is a handle that additionally has iterator_traits<T>, and movement functions dependant on iterator_category. indirect_iterator<T> requires that T is a valid iterator and that iterator_traits<T>::value_type is a valid handle. Seems neat to me, but who would have designed std::iterator_traits that way back then :-) -- Raoul Gough "Let there be one measure for wine throughout our kingdom, and one measure for ale, and one measure for corn" - Magna Carta

On Thu, 17 Jul 2003, David Abrahams wrote:
Raoul Gough <yg-boost-users@m.gmane.org> writes:
David Abrahams <dave@boost-consulting.com> writes:
Raoul Gough <yg-boost-users@m.gmane.org> writes: [snip]
Really seems a bit weird that boost::referent wasn't already invented in the type_traits portion of the library, since it can be applied to any kind of pointer, iterator, etc... Anyway, it has neatened up my code quite a bit, thanks.
It's a little quirky, yet. If you define an iterator with a nested element_type member it will do the wrong thing.
I guess in an ideal world, we would have something like this:
template<typename T> struct handle_traits { typedef typename T::value_type value_type; typedef typename T::pointer_type pointer_type; typedef typename T::reference_type reference_type; };
template<typename T> struct iterator_traits : public handle_traits<T> { typedef typename T::iterator_category iterator_category; typedef typename T::difference_type difference_type; };
I don't see why that's preferable to what we have now with referent.
As an outsider to your development process, the above is a lot easier to understand. The problem you're trying to fix is (mostly) clear at first glance. A "referent," on the other hand, is an underused wording/concept, and IMO, harder to comprehend. -tim
participants (3)
-
David Abrahams
-
Raoul Gough
-
Tim Robertson