Limitations / Flaws with transformed_range

I've already noted that the "transformed_range", the class behind
boost::adaptors::transform, is not using result_of as documented but seems to be simply
looking for result_type, period.
I've found another issue, and I consider it a "flaw" because it is a Limitation due to
oversight or an artificial restriction, and the deeper workings should handle these cases
just fine. Let me explain in detail:
The
template< class F, class R >
struct transformed_range :
takes two arguments. The R argument is used for two purposes. It gives the iterator type
that will be held, via range_iterator<R>::type. It also gives the exact type of the
argument expected by the constructor.
Now here is an example from my experiments / work-in-progress:
template< class Range >
inline transformed_range

Hi,
I've already noted that the "transformed_range", the class behind boost::adaptors::transform, is not using result_of as documented but seems to be simply looking for result_type, period.
boost::adaptors::transform using result_of now(Boost 1.47.0). see release note: http://www.boost.org/users/history/version_1_47_0.html
Iterator: Add function_input_iterator (#2893). Bug fixes: #1427, #1517, #3434.
and change: https://svn.boost.org/trac/boost/ticket/1427
======================== Akira Takahashi mailto:faithandbrave@gmail.com blog: http://d.hatena.ne.jp/faith_and_brave/

I've found another issue, and I consider it a "flaw" because it is a Limitation due to oversight or an artificial restriction, and the deeper workings should handle these cases just fine. Let me explain in detail:
The template< class F, class R > struct transformed_range :
takes two arguments. The R argument is used for two purposes. It gives the iterator type that will be held, via range_iterator<R>::type. It also gives the exact type of the argument expected by the constructor.
Now here is an example from my experiments / work-in-progress:
template< class Range > inline transformed_range
operator|( const Range& r, const ASCII_lower_forwarder ) { return transformed_range ( ASCII_lower(), // The underlying transform iterators wants this internal::src_prep(typename std::tr1::is_pointer<Range>::type() ,r) // "source" style argument processing ); } The src_prep is similar to the supplied is_literal, and used for the same purpose. It will package a primitive array as a iterator_range, handing string literals and primitive array objects in the way I intend with respect to nul terminators. It differs from is_literal in several ways, but the idea is the same.
Now I don't have to do anything to the Range parameter passed as the type argument to transformed_range, because even when I change the type of the massaged argument, it still has the same underlying iterator type. After all, it gets the iterators from the original range thing passed in.
But, the massaged value of r is rejected by the constructor, because it has a different type. It doesn't need to be the same type! It has the same underlying iterator type and could be assigned to it, but the constructor is too strict.
I don't think this "operator|" - which lives in the boost::range_detail namespace (note the "detail") - is meant to be specialized by users. Why not accomplish this "massaging" through your own range adaptor instead? As in: my_range | my_massager | transformed(ASCII_lower()) If you use this a lot, you could write a range adaptor that combines the two: my_range | ascii_lowered Regards, Nate.

On 7/19/2011 3:41 AM, Nathan Ridge wrote:
I don't think this "operator|" - which lives in the boost::range_detail namespace (note the "detail") - is meant to be specialized by users.
On the contrary. It's not specialized, but overloaded, and the instructions say to do exactly that. In particular, http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/ext... "Implement a Rage Adaptor without arguments".
Why not accomplish this "massaging" through your own range adaptor instead?
The Range docs on is_literal explain that it's used inside an algorithm implementation, not explicitly by the caller. I'm using my "prep" functions based on the nature of the argument, treating them in different ways. The ability to deal with the argument in that way is a documented part of the algorithm. The call to it is rather baroque rather than wrapped in another function that dispatches based on the tagging, because one of the differences from as_literal is that it doesn't always return the same type. as_literal reforms whatever you gave it into a iterator_range. src_prep only packs up primitive arrays and leaves other things _unchanged_. The thought is that I can pass single-use ranges and not trigger them prematurely. The simple-to-call wrapper would need another metafunction to form the return type, so I didn't bother.

I don't think this "operator|" - which lives in the boost::range_detail namespace (note the "detail") - is meant to be specialized by users.
On the contrary. It's not specialized, but overloaded, and the instructions say to do exactly that. In particular, http://www.boost.org/doc/libs/1_46_1/libs/range/doc/html/range/reference/ext... "Implement a Rage Adaptor without arguments".
I'm sorry, I misread your code. I saw the return type was transformed_range and so I thought you are somehow trying to specialize the "transformed" adaptor's operator| to behave differently when you do "my_range | transformed(ASCII_lower())". Looking at it again, it seems what you are really trying to do is write your own adaptor "ASCII_lowered" or something similar that would be used as "my_range | ASCII_lowered" (which is precisely what I was suggesting). Now, regarding your problem (which I now understand):
template< class Range > inline transformed_range
operator|( const Range& r, const ASCII_lower_forwarder ) { return transformed_range ( ASCII_lower(), // The underlying transform iterators wants this internal::src_prep(typename std::tr1::is_pointer<Range>::type() ,r) // "source" style argument processing ); }
As you discovered, returning transformed_range

On 7/19/2011 6:10 PM, Nathan Ridge wrote:
Looking at it again, it seems what you are really trying to do is write your own adaptor "ASCII_lowered" or something similar that would be used as "my_range | ASCII_lowered" (which is precisely what I was suggesting).
Right.
As you discovered, returning transformed_range
won't work because src_prep() does not return "const Range", it returns something else. I see 3 solutions:
Updating the transformed_range constructor to take a template argument, as I showed, works perfectly, and is simpler than anything else. That's why I suggest that this be applied to the Boost code. Is there a way for a mere user to submit that formally?

On Wed, Jul 20, 2011 at 11:26, John M. Dlugosz
Updating the transformed_range constructor to take a template argument, as I showed, works perfectly, and is simpler than anything else. That's why I suggest that this be applied to the Boost code. Is there a way for a mere user to submit that formally?
you can submit it to the trac tracker. Best, Dee

Updating the transformed_range constructor to take a template argument, as I showed, works perfectly, and is simpler than anything else.
This only works if the other range type happens to have the same iterator type. IMO this is a rare situation - most range types have their own iterator types.
That's why I suggest that this be applied to the Boost code. Is there a way for a mere user to submit that formally?
You can open a new ticket in the Boost Issue Tracker [1], and attach a patch implementing this. Regards, Nate. [1] https://svn.boost.org/trac/boost
participants (4)
-
Akira Takahashi
-
Diederick C. Niehorster
-
John M. Dlugosz
-
Nathan Ridge