Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the effect of the pipe operator in c++ boost::adaptors::filtered?

Tags:

c++

boost

In boost::adaptors::filtered the filter function is used likeso:

std::vector<int> input;
input += 1,2,3,4,5,6,7,8,9;

boost::copy(
        input | filtered(is_even()),
        std::ostream_iterator<int>(std::cout, ","));

What is the effect of the pipe operator in this case? It is not defined for std::vector, is it an overload? If so, how does one effectively search for such operators in libraires like boost?

like image 684
wellnoidea Avatar asked Apr 04 '18 19:04

wellnoidea


1 Answers

This is a Boost Range Adaptor. Some more documentation has been written in this online book "The Boost C++ Libraries".

There are many such ranges, which can be composed to write high-level functional effect. Examples are here:

  • Why is there no transform_if in the C++ standard library?
  • Is it possible to use boost::filter_iterator for output?

The filtered adaptor

input | filtered(is_even()) creates a temporary instance of the adaptor type:

boost::range_detail::filtered_range<is_even, std::vector<int> >

That's a type that models the Range Concept and holds a reference to the source range (input) as well as a copy of the filter predicate (is_even()).

The Range Concept is then implemented such that iteration of the range yields a bidirectional range as if it had only the elements of the source range that satisfy the filter predicate. You could equally write:

is_even predicate;
for (auto const& i : input)
    if (predicate(i))
        std::cout << i << ",";

range | adaptor is an expression template that generates a new adapted range.

How/Why Does It Work With |?

The real answer is "because that's how it's designed and documented". The more technical explanation is because filtered(is_even()) is of type boost::range_detail::filter_holder<is_even> which has an overloaded operator |:

template< class SinglePassRange, class Predicate >
inline filtered_range<Predicate, SinglePassRange>
operator|(SinglePassRange& r,
          const filter_holder<Predicate>& f)
{
    BOOST_RANGE_CONCEPT_ASSERT((SinglePassRangeConcept<SinglePassRange>));
    return filtered_range<Predicate, SinglePassRange>( f.val, r );
}

Note: The assert only verifies the minimum required traversal category. As documented you'll get "The minimum of the range category of rng and Bidirectional Range", which is a Bidirectional Range in this case (because vector has random traversal).

The Other Thing

I am already lost at input += 1,2,.... – user463035818 56 mins ago

That's Boost Assign, unrelated to the range adaptor, I'd venture that C++11 makes it largely obsolete, because you can easily say

std::vector<int> input { 1, 2, 3, 4, 5, 6, 7, 8, 9 };

Or indeed

std::vector<int> input;
input.insert(input.end(), { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
like image 172
sehe Avatar answered Nov 15 '22 09:11

sehe