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/extending/method_3/method_3_1.html> "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<ASCII_lower,const Range> operator|( const Range& r, const ASCII_lower_forwarder ) { return transformed_range<ASCII_lower,const 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<ASCII_lower, const Range> won't work because src_prep() does not return "const Range", it returns something else. I see 3 solutions: 1) Write a metafunction "src_prep_result" that computes the return type of src_prep() on input Range, and the return: transformed_range<ASCII_lower, typename src_prep_result<Range>::type> 2) [C++0x only] Use decltype to figure out what src_prep returns, i.e. return: transformed_range<ASCII_lower, decltype(internal::src_prep(typename std::tr1::is_pointer<Range>::type(), r))> If you can't use C++0x, you may want to try the BOOST_TYPEOF() macro which emulates it. I'm not sure how well it works. 3) If, as you say, the iterator types of "Range" and the return type of src_prep() are the same, you can return an iterator_range, as follows (untested): template <typename Range> iterator_range<typename range_iterator<Range>::type> convert_to_iterator_range(const Range& r) { return iterator_range<typename range_iterator<Range>::type>(begin(r), end(r)); } template< class Range > inline transformed_range<ASCII_lower, const iterator_range<typename range_iterator<Range>::type> > operator|( const Range& r, const ASCII_lower_forwarder ) { return transformed_range<ASCII_lower, const iterator_range<typename range_iterator<Range>::type> >( ASCII_lower(), convert_to_iterator_range(internal::src_prep(typename std::tr1::is_pointer<Range>::type(), r)) ); } Regards, Nate.