Ticket #7630: boost-range.patch

File boost-range.patch, 24.8 KB (added by Jeffrey Yasskin <jyasskin@…>, 9 years ago)

Patch demonstrating the fix on boost::adaptors::filtered

  • boost/range/adaptor/extend_temporary.hpp

     
     1// Boost.Range library
     2//
     3//  Copyright Google 2013. Use, modification and
     4//  distribution is subject to the Boost Software License, Version
     5//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
     6//  http://www.boost.org/LICENSE_1_0.txt)
     7//
     8// For more information, see http://www.boost.org/libs/range/
     9//
     10
     11#ifndef BOOST_RANGE_ADAPTOR_EXTEND_TEMPORARY_HPP
     12#define BOOST_RANGE_ADAPTOR_EXTEND_TEMPORARY_HPP
     13
     14#include <boost/config.hpp>
     15
     16namespace boost
     17{
     18    // Pass a template argument that has been deduced as an rvalue
     19    // reference, and std::forward the function argument.
     20    // extend_temporary<T> will move temporaries into a member
     21    // variable, but not store anything for non-temporaries.
     22    //
     23    // Call this->extended(function_arg) to get a reference to either
     24    // the lifetime-extended temporary or the lvalue argument.
     25    template< class T >
     26    struct extend_temporary
     27    {
     28    private:
     29        T extended_;
     30    protected:
     31#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
     32        // No need to provide an alternative for C++98: they'll all
     33        // use the specialization below.
     34        extend_temporary(T&& to_extend) : extended_(std::forward<T>(to_extend))
     35        { }
     36#endif
     37        T& extended(T&)
     38        { return extended_; }
     39    };
     40
     41    template< class T >
     42    struct extend_temporary< T& >
     43    {
     44        // Empty.
     45    protected:
     46        extend_temporary(T&)
     47        { }
     48
     49        T& extended(T& lval)
     50        { return lval; }
     51    };
     52}
     53
     54#endif  // BOOST_RANGE_ADAPTOR_EXTEND_TEMPORARY_HPP
  • boost/range/adaptor/filtered.hpp

     
    11// Boost.Range library
    22//
    3 //  Copyright Thorsten Ottosen, Neil Groves 2006 - 2008. Use, modification and
     3//  Copyright Thorsten Ottosen, Neil Groves 2006 - 2008, Google 2013. Use, modification and
    44//  distribution is subject to the Boost Software License, Version
    55//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
    66//  http://www.boost.org/LICENSE_1_0.txt)
     
    1212#define BOOST_RANGE_ADAPTOR_FILTERED_HPP
    1313
    1414#include <boost/range/adaptor/argument_fwd.hpp>
     15#include <boost/range/adaptor/extend_temporary.hpp>
    1516#include <boost/range/iterator_range.hpp>
    1617#include <boost/iterator/filter_iterator.hpp>
    1718
    namespace boost  
    1920{
    2021    namespace range_detail
    2122    {
     23        // Note that R is an lvalue reference type if the filter was
     24        // passed an lvalue range.
    2225        template< class P, class R >
    2326        struct filtered_range :
    24             boost::iterator_range<
     27            private boost::extend_temporary<R>,
     28            public boost::iterator_range<
    2529                boost::filter_iterator< P,
    2630                    BOOST_DEDUCED_TYPENAME range_iterator<R>::type
    2731                >
    namespace boost  
    3438                        >
    3539                    > base;
    3640        public:
    37             filtered_range( P p, R& r )
    38             : base( make_filter_iterator( p, boost::begin(r), boost::end(r) ),
    39                     make_filter_iterator( p, boost::end(r), boost::end(r) ) )
     41#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
     42            filtered_range( P p, R&& r )
     43            : extend_temporary<R>(std::forward<R>(r)),
     44#else  // BOOST_NO_CXX11_RVALUE_REFERENCES
     45            filtered_range( P p, R r )
     46            : extend_temporary<R>(r),
     47#endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
     48              base( make_filter_iterator( p, boost::begin(this->extended(r)), boost::end(this->extended(r)) ),
     49                    make_filter_iterator( p, boost::end(this->extended(r)), boost::end(this->extended(r)) ) )
    4050            { }
    4151        };
    4252
    namespace boost  
    4757            { }
    4858        };
    4959
     60#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
    5061        template< class InputRng, class Predicate >
    5162        inline filtered_range<Predicate, InputRng>
     63        operator|( InputRng&& r,
     64                   const filter_holder<Predicate>& f )
     65        {
     66            return filtered_range<Predicate, InputRng>(
     67                f.val, std::forward<InputRng>(r) );
     68        }
     69#else  // BOOST_NO_CXX11_RVALUE_REFERENCES
     70        template< class InputRng, class Predicate >
     71        inline filtered_range<Predicate, InputRng&>
    5272        operator|( InputRng& r,
    5373                   const filter_holder<Predicate>& f )
    5474        {
    55             return filtered_range<Predicate, InputRng>( f.val, r );
     75            return filtered_range<Predicate, InputRng&>( f.val, r );
    5676        }
    5777
    5878        template< class InputRng, class Predicate >
    59         inline filtered_range<Predicate, const InputRng>
     79        inline filtered_range<Predicate, const InputRng&>
    6080        operator|( const InputRng& r,
    6181                   const filter_holder<Predicate>& f )
    6282        {
    63             return filtered_range<Predicate, const InputRng>( f.val, r );
     83            return filtered_range<Predicate, const InputRng&>( f.val, r );
    6484        }
     85#endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
    6586
    6687    } // 'range_detail'
    6788
    namespace boost  
    81102                       range_detail::forwarder<range_detail::filter_holder>();
    82103        }
    83104
     105#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
    84106        template<class InputRange, class Predicate>
    85107        inline filtered_range<Predicate, InputRange>
    86         filter(InputRange& rng, Predicate filter_pred)
     108        filter(InputRange&& rng, Predicate filter_pred)
    87109        {
    88110            return range_detail::filtered_range<Predicate, InputRange>( filter_pred, rng );
    89111        }
     112#else  // BOOST_NO_CXX11_RVALUE_REFERENCES
     113        template<class InputRange, class Predicate>
     114        inline filtered_range<Predicate, InputRange&>
     115        filter(InputRange& rng, Predicate filter_pred)
     116        {
     117            return range_detail::filtered_range<Predicate, InputRange&>( filter_pred, rng );
     118        }
    90119
    91120        template<class InputRange, class Predicate>
    92         inline filtered_range<Predicate, const InputRange>
     121        inline filtered_range<Predicate, const InputRange&>
    93122        filter(const InputRange& rng, Predicate filter_pred)
    94123        {
    95             return range_detail::filtered_range<Predicate, const InputRange>( filter_pred, rng );
     124            return range_detail::filtered_range<Predicate, const InputRange&>( filter_pred, rng );
    96125        }
     126#endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
    97127    } // 'adaptors'
    98128
    99129}
  • boost/range/iterator.hpp

     
    11// Boost.Range library
    22//
    3 //  Copyright Thorsten Ottosen 2003-2004. Use, modification and
     3//  Copyright Thorsten Ottosen 2003-2004, Google 2013. Use, modification and
    44//  distribution is subject to the Boost Software License, Version
    55//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
    66//  http://www.boost.org/LICENSE_1_0.txt)
     
    2020#include <boost/range/const_iterator.hpp>
    2121#include <boost/type_traits/is_const.hpp>
    2222#include <boost/type_traits/remove_const.hpp>
     23#include <boost/type_traits/remove_reference.hpp>
    2324#include <boost/mpl/eval_if.hpp>
    2425
    2526namespace boost
    namespace boost  
    5051    template< typename C >
    5152    struct range_iterator
    5253    {
     54        typedef BOOST_RANGE_DEDUCED_TYPENAME
     55                remove_reference<C>::type without_reference;
    5356#if BOOST_WORKAROUND(BOOST_MSVC, == 1310)
    5457 
    5558        typedef BOOST_RANGE_DEDUCED_TYPENAME 
    56                range_detail_vc7_1::range_iterator<C>::type type; 
     59                range_detail_vc7_1::range_iterator<without_reference>::type type; 
    5760           
    5861#else 
    5962
    6063        typedef BOOST_RANGE_DEDUCED_TYPENAME
    61             mpl::eval_if_c< is_const<C>::value,
    62                             range_const_iterator< typename remove_const<C>::type >,
    63                             range_mutable_iterator<C> >::type type;
     64            mpl::eval_if_c< is_const<without_reference>::value,
     65                            range_const_iterator< typename remove_const<without_reference>::type >,
     66                            range_mutable_iterator<without_reference> >::type type;
    6467       
    6568#endif         
    6669    };
  • libs/range/doc/reference/adaptors/filtered.qbk

     
    11[/
    2     Copyright 2010 Neil Groves
     2    Copyright 2010 Neil Groves, 2013 Google
    33    Distributed under the Boost Software License, Version 1.0.
    44    (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    55/]
     
    1515* [*Postcondition:] For all adjacent elements `[x]` in the returned range, `pred(x)` is `true`.
    1616* [*Throws:] Whatever the copy constructor of `pred` might throw.
    1717* [*Range Category:] __forward_range__
    18 * [*Range Return Type:] `boost::filtered_range<typeof(rng)>`
    1918* [*Returned Range Category:] The minimum of the range category of `rng` and __bidirectional_range__
    2019
    2120[section:filtered_example filtered example]
  • libs/range/doc/reference/adaptors.qbk

     
    11[/
    2     Copyright 2010 Neil Groves
     2    Copyright 2010 Neil Groves, 2013 Google
    33    Distributed under the Boost Software License, Version 1.0.
    44    (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    55/]
    Also note that `boost::range_value<R>::type` must  
    143143
    144144Range Category in the following adaptor descriptions refers to the minimum range concept required by the range passed to the adaptor. The resultant range is a model of the same range concept as the input range unless specified otherwise.
    145145
    146 Returned Range Category is the concept of the returned range. In some cases the returned range is of a lesser category than the range passed to the adaptor. For example, the `filtered` adaptor returns only a `ForwardRange` regardless of the input.
     146Returned Range Category is the concept of the returned range. In some cases the returned range is of a lesser category than the range passed to the adaptor. For example, the `filtered` adaptor returns at most a `BidirectionalRange` regardless of the input.
    147147
    148148Furthermore, the following rules apply to any expression of the form
    149149``
    150150rng | boost::adaptors::adaptor_generator
    151151``
    152152
    153 1. Applying `operator|()` to a range `R` (always left argument) and a range adapter `RA` (always right argument) yields a new range type which may not conform to the same range concept as `R`.
     153# Applying `operator|()` to a range `R` (always left argument) and a range adapter `RA` (always right argument) yields a new range type which may not conform to the same range concept as `R`.
    154154
    155 2. The return-type of `operator|()` is otherwise unspecified.
     155# The return-type of `operator|()` is otherwise unspecified.
    156156
    157 3. `operator|()` is found by Argument Dependent Lookup (ADL) because a range adaptor is implemented in namespace `boost::adaptors`.
     157# `operator|()` is found by Argument Dependent Lookup (ADL) because a range adaptor is implemented in namespace `boost::adaptors`.
    158158
    159 4. `operator|()` is used to add new behaviour ['*lazily*] and never modifies its left argument.
     159# When compiled in at least C++11 and passed a temporary (rvalue) range as the left argument, `operator|()` will move the range into its return value.
    160160
    161 5. All iterators extracted from the left argument are extracted using qualified calls to `boost::begin()` and `boost::end()`.
     161# `operator|()` is used to add new behaviour ['*lazily*], and never modifies its left argument, except possibly to move it as mentioned above.
    162162
    163 6. In addition to the `throw`-clauses below, `operator|()` may throw exceptions as a result of copying iterators. If such copying cannot throw an exception, then neither can the whole expression.
     163# All iterators extracted from the left argument are extracted using qualified calls to `boost::begin()` and `boost::end()`.
    164164
     165# In addition to the `throw`-clauses below, `operator|()` may throw exceptions as a result of copying iterators or moving rvalue ranges. If such copying or moving cannot throw an exception, then neither can the whole expression.
     166
    165167[endsect]
    166168
    167169[section:reference Reference]
  • libs/range/doc/reference/extending.qbk

     
    11[/
    2     Copyright 2010 Neil Groves
     2    Copyright 2010 Neil Groves, 2013 Google
    33    Distributed under the Boost Software License, Version 1.0.
    44    (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    55/]
    To implement a Range Adaptor without arguments (e.  
    171171# Provide a range for your return type, for example:
    172172``
    173173#include <boost/range/iterator_range.hpp>
     174#include <boost/range/adaptor/extend_temporary.hpp>
    174175#include <boost/iterator/reverse_iterator.hpp>
    175176
    176177template< typename R >
    177178struct reverse_range :
    178     boost::iterator_range<
     179    private boost::extend_temporary<R>,
     180    public boost::iterator_range<
    179181        boost::reverse_iterator<
    180182            typename boost::range_iterator<R>::type> >
    181183{
    struct reverse_range :  
    188190    typedef boost::reverse_iterator<
    189191        typename boost::range_iterator<R>::type > iterator;
    190192
    191     reverse_range(R& r)
    192         : base(iterator(boost::end(r)), iterator(boost::begin(r)))
     193    reverse_range(R&& r)
     194        : boost::extend_temporary<R>(std::forward<R>(r)),
     195          base(iterator(boost::end(this->extended(r))),
     196               iterator(boost::begin(this->extended(r))))
    193197    { }
    194198};
    195199``
    namespace detail {  
    205209``
    206210template< class BidirectionalRng >
    207211inline reverse_range<BidirectionalRng>
    208 operator|( BidirectionalRng& r, detail::reverse_forwarder )
     212operator|( BidirectionalRng&& r, detail::reverse_forwarder )
    209213{
    210         return reverse_range<BidirectionalRng>( r );
     214        return reverse_range<BidirectionalRng>( std::forward<BidirectionalRng>(r) );
    211215}
    212 
    213 template< class BidirectionalRng >
    214 inline reverse_range<const BidirectionalRng>
    215 operator|( const BidirectionalRng& r, detail::reverse_forwarder )
    216 {
    217         return reverse_range<const BidirectionalRng>( r );
    218 }
    219216``
    220217
    221218# Declare the adaptor itself (it is a variable of the tag type).
    class replace_value  
    259256
    260257template<typename Range>
    261258class replace_range
    262 : public boost::iterator_range<
    263     boost::transform_iterator<
     259: private boost::extend_temporary<Range>,
     260  public boost::iterator_range<
     261    public boost::transform_iterator<
    264262        replace_value<typename boost::range_value<Range>::type>,
    265263        typename boost::range_iterator<Range>::type> >
    266264{
    class replace_range  
    272270    typedef boost::iterator_range<replaced_iterator> base_t;
    273271
    274272public:
    275     replace_range(Range& rng, value_type from, value_type to)
    276         : base_t(replaced_iterator(boost::begin(rng), Fn(from,to)),
    277                  replaced_iterator(boost::end(rng), Fn(from,to)))
     273    replace_range(Range&& rng, value_type from, value_type to)
     274        : boost::extend_temporary<Range>(std::forward<Range>(rng)),
     275          base_t(replaced_iterator(boost::begin(this->extended(rng)), Fn(from,to)),
     276                 replaced_iterator(boost::end(this->extended(rng)), Fn(from,to)))
    278277     {
    279278     }
    280279 };
    replaced = boost::range_detail::forwarder2<replace  
    305304``
    306305template<typename SinglePassRange>
    307306inline replace_range<SinglePassRange>
    308 operator|(SinglePassRange& rng,
     307operator|(SinglePassRange&& rng,
    309308          const replace_holder<typename boost::range_value<SinglePassRange>::type>& f)
    310309{
    311     return replace_range<SinglePassRange>(rng, f.val1, f.val2);
     310    return replace_range<SinglePassRange>(std::forward<SinglePassRange>(rng), f.val1, f.val2);
    312311}
    313 
    314 template<typename SinglePassRange>
    315 inline replace_range<const SinglePassRange>
    316 operator|(const SinglePassRange& rng,
    317           const replace_holder<typename boost::range_value<SinglePassRange>::type>& f)
    318 {
    319     return replace_range<const SinglePassRange>(rng, f.val1, f.val2);
    320 }
    321312``
    322313
    323314[endsect]
  • libs/range/doc/reference/utilities.qbk

     
    11[/
    2     Copyright 2010 Neil Groves
     2    Copyright 2010 Neil Groves, 2013 Google
    33    Distributed under the Boost Software License, Version 1.0.
    44    (See accompanying file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
    55/]
    Having an abstraction that encapsulates a pair of  
    99
    1010* Class `iterator_range`
    1111* Class `sub_range`
    12 * Function `join`
    1312
    1413The `iterator_range` class is templated on an __forward_traversal_iterator__ and should be used whenever fairly general code is needed. The `sub_range` class is templated on an __forward_range__ and it is less general, but a bit easier to use since its template argument is easier to specify. The biggest difference is, however, that a `sub_range` can propagate constness because it knows what a corresponding `const_iterator` is.
    1514
    1615Both classes can be used as ranges since they implement the __minimal_interface__ required for this to work automatically.
    1716
     17This library also provides two further utilities:
     18
     19* Function `join`
     20* Class `extend_temporary`
     21
     22
    1823[section:iterator_range Class `iterator_range`]
    1924
    2025The intention of the `iterator_range` class is to encapsulate two iterators so they fulfill the __forward_range__ concept. A few other functions are also provided for convenience.
    The expression `join(irange(0,5), irange(5,10))` w  
    303308
    304309[endsect]
    305310
     311[section:extend_temporary Class `extend_temporary`]
     312
     313C++11 added the ability to easily capture expression templates into local variables:
     314
     315``
     316auto&& new_range = MakeVector() | filtered(pred) | reversed;
     317``
     318
     319However, the above statement includes two temporaries (`MakeVector()` and `MakeVector() | filtered(pred)`) that are destroyed at the end of the statement\u2014well before `new_range` is destroyed. The solution is to detect temporaries with rvalue reference parameters and move them into the adapted range.
     320
     321The simplest way of doing this stores a `T&` field in the return value of `lvalue | adaptor`.  This is fine if the adaptor needs to store a reference regardless, but most of the adaptors in this library already store iterators in their member variables, which makes the extra `T&` field a waste of space.  To fix this, we provide the `extend_temporary<left_argument_type>` class, which is empty in the case of an lvalue left argument.
     322
     323[h4 Synopsis]
     324
     325``
     326namespace boost
     327{
     328    template< class LeftArgumentType >
     329    class extend_temporary
     330    {
     331    LeftArgumentType storage;  // Exposition only; absent if LeftArgumentType is an lvalue reference.
     332
     333    public:  // construction
     334        extend_temporary( LeftArgumentType&& forwarded_left_argument );
     335
     336    public:  // access
     337        LeftArgumentType& extended(LeftArgumentType& lvalue_left_argument);
     338    };
     339} // namespace 'boost'
     340``
     341
     342`extend_temporary<T&>` is an empty class.
     343
     344This class is used as follows:
     345
     346``
     347#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
     348template< class P, class Range > struct filtered_range;
     349
     350template< class Range, class Predicate >
     351inline filtered_range<Predicate, Range>
     352operator|( Range&& r,  // <- Note deduced rvalue reference.
     353           const filter_holder<Predicate>& f )
     354{
     355    return filtered_range<Predicate, Range>(  // <- Instantiate filtered_range with template param.
     356        f.val, std::forward<Range>(r) );  // <- Forward argument into constructor.
     357}
     358
     359template< class P, class Range >
     360struct filtered_range :
     361    private boost::extend_temporary<Range>, ...
     362{
     363    filtered_range( P p, Range&& r )
     364    : extend_temporary<Range>(std::forward<Range>(r)),
     365      impl(this->extended(r)) {}  // <- Use a reference either to the lifetime-extended
     366                                  // argument or the direct argument.
     367};
     368#endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
     369``
     370
     371# Define a function template taking a deduced rvalue reference parameter (`Range`), so that the template parameter becomes an lvalue reference for named arguments but a non-reference for temporary arguments.
     372
     373# Define a wrapper struct template`<Range>` that inherits from `extend_temporary<Range>`.
     374
     375# Pass the unmodified template parameter to the wrapper struct.
     376
     377# Pass `std::forward<Range>(function_arg)` into the wrapper struct and thence into `extend_temporary<Range>`.
     378
     379# In the constructor of the wrapper struct, anywhere you need to use a reference to the argument's value, use `this->extended(function_arg)` instead, to get a reference to the internal storage when necessary.
     380
     381
     382In C++98 mode, you can either drop the use of `extend_temporary` entirely, or you can instantiate it with lvalue references to turn it off:
     383
     384``
     385#ifdef BOOST_NO_CXX11_RVALUE_REFERENCES
     386template< class P, class Range > struct filtered_range;
     387
     388// Both const and non-const lvalue reference overloads:
     389template< class Range, class Predicate >
     390inline filtered_range<Predicate, Range&>  // Range&, not just Range.
     391operator|( Range& r,
     392           const filter_holder<Predicate>& f )
     393{
     394    // And pass exactly the argument type and value into filtered_range:
     395    return filtered_range<Predicate, Range&>( f.val, r );
     396}
     397
     398template< class Range, class Predicate >
     399inline filtered_range<Predicate, const Range&>  // const Range&, not just Range.
     400operator|( const Range& r,
     401           const filter_holder<Predicate>& f )
     402{
     403    return filtered_range<Predicate, const Range&>( f.val, r );
     404}
     405
     406template< class P, class Range >
     407struct filtered_range :
     408    private boost::extend_temporary<Range>, ...
     409{
     410    filtered_range( P p, Range r )  // <- Remember that Range is a reference type in this case.
     411    : extend_temporary<Range>(r),
     412      impl(this->extended(r)) {}  // <- Returns 'r' since 'Range' is a reference.
     413};
     414#endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
     415``
     416
     417[h4 Details member functions]
     418
     419`extend_temporary( LeftArgumentType&& );`
     420
     421[:['[*Effects]] If `LeftArgumentType&&` is an rvalue reference, moves it into `storage`. If `LeftArgumentType&&` is an lvalue reference, has no effect.]
     422
     423`LeftArgumentType& extended(LeftArgumentType& orig_arg]`
     424
     425[:['[*Returns]] If `LeftArgumentType` is a lvalue reference, `orig_arg`. Otherwise `storage`.]
     426
    306427[endsect]
    307428
     429[endsect]
     430
  • libs/range/test/adaptor_test/filtered.cpp

     
    11// Boost.Range library
    22//
    3 //  Copyright Neil Groves 2009. Use, modification and
     3//  Copyright Neil Groves 2009, Google 2013. Use, modification and
    44//  distribution is subject to the Boost Software License, Version
    55//  1.0. (See accompanying file LICENSE_1_0.txt or copy at
    66//  http://www.boost.org/LICENSE_1_0.txt)
    namespace boost  
    8383                                           reference_result.end(),
    8484                                           test_result2.begin(),
    8585                                           test_result2.end() );
     86
     87#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
     88            // Check that temporary arguments can be captured into
     89            // either an auto-typed variable or a range-based for
     90            // loop.
     91#ifndef BOOST_NO_CXX11_AUTO_DECLARATIONS
     92            std::vector< value_t > test_result3;
     93            auto filter_result = Container(c) | filtered(pred);
     94            boost::push_back(test_result3, filter_result);
     95            BOOST_CHECK_EQUAL_COLLECTIONS( reference_result.begin(),
     96                                           reference_result.end(),
     97                                           test_result3.begin(),
     98                                           test_result3.end() );
     99#endif
     100
     101#ifndef BOOST_NO_CXX11_RANGE_BASED_FOR
     102            std::vector< value_t > test_result4;
     103            for (const value_t& elem : Container(c) | filtered(pred))
     104                test_result4.push_back( elem );
     105            BOOST_CHECK_EQUAL_COLLECTIONS( reference_result.begin(),
     106                                           reference_result.end(),
     107                                           test_result4.begin(),
     108                                           test_result4.end() );
     109#endif
     110#endif  // BOOST_NO_CXX11_RVALUE_REFERENCES
    86111        }
    87112
    88113        template< class Container, class Pred >