|
Boost : |
From: Howard Hinnant (howard.hinnant_at_[hidden])
Date: 2006-04-15 16:36:51
On Apr 15, 2006, at 3:06 PM, Daniel Walker wrote:
> On 4/15/06, David Abrahams <dave_at_[hidden]> wrote:
>> "Daniel Walker" <daniel.j.walker_at_[hidden]> writes:
>>
>>> On 4/11/06, David Abrahams <dave_at_[hidden]> wrote:
>>>> Thorsten Ottosen <thorsten.ottosen_at_[hidden]> writes:
>>>>
>>>>>> cannot have overloads (in C++98) taking containers/ranges:
>>>>>>
>>>>>> fn( Iterator first, Iterator last )
>>>>>> fn( Iterator first, Iterator last, Functor f )
>>>>>> fn( Range rng )
>>>>>> fn( Range rng, Functor f )
>>>>>>
>>>>>> as the last overload is ambiguous. Concepts will allow this to
>>>>>> be resolved
>>>>>> as a Functor will not match the Iterator requirements :).
>>>>>
>>>>> you can use enable_if on the latter and disable it the two
>>>>> types are the
>>>>> same.
>>>>
>>>> Not if you happen to have a type that is both a valid range and a
>>>> valid function object.
>>>>
>>>> Yes, that's a corner case, but it's the corner of a large floating
>>>> block of ice.
>>>
>>> For this idiom, I use boost::iterator_range like so,
>>>
>>> fn( Iterator first, Iterator last )
>>> fn( Iterator first, Iterator last, Functor f )
>>> fn( boost::iterator_range<Iterator> rng )
>>> fn( boost::iterator_range<Iterator> rng, Functor f )
>>
>> This is not generic. Now you can't pass other valid Ranges
>> (e.g. std::vector<T>) as the first argument to fn.
>
> Yeah, I know. This is just a work-around because the generic version
> isn't possible today due to the overload ambiguity. You can indirectly
> use the functions with other valid Ranges like vector, but it's a
> hassle because you first have to convert them using
> make_iterator_range(). In some circumstances, for the time being, this
> may be acceptable for this particular idiom (overloading algorithms to
> take both iterators and ranges), but really I agree that it further
> illustrates the need for in-language support for concepts in a future
> version of C++ in order to make the overloads generic.
Actually in this particular case, all we need is a more smartly
designed std::iterator_traits class:
Spec:
--- template <class Iterator> struct iterator_traits { }; However if Iterator has the nested types: difference_type, value_type, pointer, reference and iterator_category, and if Iterator::iterator_category (if it exists) is implicitly convertible to either std::input_iterator_tag, or std::output_iterator_tag, then the struct iterator_traits is instead: template <class Iterator> struct iterator_traits { typedef typename Iterator::difference_type difference_type; typedef typename Iterator::value_type value_type; typedef typename Iterator::pointer pointer; typedef typename Iterator::reference reference; typedef typename Iterator::iterator_category iterator_category; }; Plus the pointer specializations... Plus any user-defined specializations... --- Such an iterator_traits is easy to implement today with has_member_* and is_convertible. And now you can say iterator_traits<any type at all>. The instantiation always compiles and may or may not have the nested typedefs. Then you can make an is_input_iterator trait: A type T is an input iterator if iterator_traits<T> has a member called iterator_category that is convertible to std::input_iterator_tag. enable_if your fn with is_input_iterator<InputIterator>, and you're done. You can get most of the way there with today's iterator_traits. You'll miss user-defined iterators that specialize iterator_traits instead of containing the nested types directly (which is practically no types at all). Just change is_iterator to look for the nested types, and then specialize is_iterator for pointer types. Then you can build is_input_iterator on top of is_iterator. That's not an argument against concepts. Its just a fun and useful exercise to build is_input_iterator<T>. Maybe someone can see a better way to do it with today's iterator_traits than what I've described. -Howard
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk