Index: boost/range/adaptor/transformed.hpp =================================================================== --- boost/range/adaptor/transformed.hpp (revision 81545) +++ boost/range/adaptor/transformed.hpp (working copy) @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -48,6 +49,18 @@ { } }; + template< class R, class T, class U > + struct ret_wrapper + { + T val; + explicit ret_wrapper(T v) : val(v) {} + + typedef R result_type; + + R operator()(U u) const + { return val(u); } + }; + template< class T > struct transform_holder : holder { @@ -55,6 +68,36 @@ { } }; + template< class R, class T > + struct ret_transform_holder : transform_holder + { + ret_transform_holder( T r ) : transform_holder(r) + { } + }; + + + template< class InputRng, class R, class UnaryFunction > + inline transformed_range::type>, InputRng> + operator|( InputRng& r, + const ret_transform_holder& f ) + { + typedef BOOST_DEDUCED_TYPENAME range_reference::type InRef; + return transformed_range, + InputRng>( ret_wrapper(f.val), r ); + } + + template< class InputRng, class R, class UnaryFunction > + inline transformed_range::type>, const InputRng> + operator|( const InputRng& r, + const ret_transform_holder& f ) + { + typedef BOOST_DEDUCED_TYPENAME range_reference::type InRef; + return transformed_range, + const InputRng>( ret_wrapper(f.val), r ); + } + template< class InputRng, class UnaryFunction > inline transformed_range operator|( InputRng& r, @@ -77,13 +120,36 @@ namespace adaptors { - namespace + template< class R, class T > + range_detail::ret_transform_holder transformed( T t ) { - const range_detail::forwarder - transformed = - range_detail::forwarder(); + return range_detail::ret_transform_holder(t); } + template< class T > + range_detail::transform_holder transformed( T t ) + { + return range_detail::transform_holder(t); + } + template< class R, class InputRng, class UnaryFunction > + inline transformed_range::type>,InputRng> + transform(InputRng& r, UnaryFunction fn) + { + typedef BOOST_DEDUCED_TYPENAME range_reference::type InRef; + return transformed_range, + InputRng>(range_detail::ret_wrapper(fn), r ); + } + template< class R, class InputRng, class UnaryFunction > + inline transformed_range::type>, const InputRng> + transform(const InputRng& r, UnaryFunction fn) + { + typedef BOOST_DEDUCED_TYPENAME range_reference::type InRef; + return transformed_range, + const InputRng>(range_detail::ret_wrapper(fn), r ); + } + template inline transformed_range transform(InputRange& rng, UnaryFunction fn) Index: libs/range/test/adaptor_test/transformed.cpp =================================================================== --- libs/range/test/adaptor_test/transformed.cpp (revision 81545) +++ libs/range/test/adaptor_test/transformed.cpp (working copy) @@ -92,6 +92,41 @@ transformed_test_impl< std::set< int > >(); transformed_test_impl< std::multiset< int > >(); } + + //Unmodifiable struct which doesn't follow result_of. + struct hands_off + { + int operator()(double d) const + { return static_cast(d); } + }; + + //Previous tests verify that transform/transformed which followed + // result_type worked. This checks only cases which don't (and thus + // require an explicit result) (assuming no decltype support) + void transformed_result_test() + { + using namespace boost::assign; + + hands_off fn; + std::vector< double > c; + c += 1,2,3,4,5,6,7,8,9; + std::vector< int > result1, result2, result3, result4; + boost::push_back(result1, c | adaptors::transformed(fn)); + boost::push_back(result2, adaptors::transform(c, fn)); + + BOOST_CHECK_EQUAL_COLLECTIONS( result1.begin(), result1.end(), + result2.begin(), result2.end() ); + + const std::vector< double >& c2 = c; + boost::push_back(result3, c2 | adaptors::transformed(fn)); + boost::push_back(result4, adaptors::transform(c2, fn)); + + BOOST_CHECK_EQUAL_COLLECTIONS( result3.begin(), result3.end(), + result4.begin(), result4.end() ); + + BOOST_CHECK_EQUAL_COLLECTIONS( result1.begin(), result1.end(), + result3.begin(), result3.end() ); + } } } @@ -102,6 +137,7 @@ = BOOST_TEST_SUITE( "RangeTestSuite.adaptor.transformed" ); test->add( BOOST_TEST_CASE( &boost::transformed_test ) ); + test->add( BOOST_TEST_CASE( &boost::transformed_result_test ) ); return test; }