# Boost :

Subject: [boost] [range][algorithms] How about making the range algorithms pipeable as the range adaptors are?
From: Viktor Sehr (viktor.sehr_at_[hidden])
Date: 2013-09-19 12:17:54

It would be syntactically really nice if the stl-algorithms wrapped in
boost range were pipeable, as with the adaptors, making it seamless to
combine them in left-to-right statements

For non-mutating algorithms I think it's an obvious evolvement
const auto& max_pos = some_range | filtered(..) | max_element;
const auto& num_elements = some_range | filtered(..) | count(42);

...instead of inside out as it is now
const auto& max_pos = max_element(some_range | filtered(..));
const auto& num_elements = count(some_range | filtered(..), 42);

For non-mutating algorithms it might not be an obvious solution, as the
range beneath is modified, but I still think it should be possible

boost::erase(my_vector | sort | unique);
boost::erase(unique(sort(my_vector));

*Implementation example with std::accumulate:*

// Tag to be recognized by the global pipe operatortemplate <typename
value_type>struct accumulate_argument_tag {
accumulate_argument_tag(const value_type& value) : value_(value) {}
const value_type& value_;
};
struct accumulate_tag {
// Put the regular algorithm as an operator() function where the
first argument is the range
template <typename range_type, typename value_type>
value_type operator()(const range_type& range, const value_type& start) {
return std::accumulate(std::begin(range), std::end(range), start);
}
// If no range is provided, return a tag which contains the
argument, which can then be identified by the global pipe operator
template <typename value_type>
accumulate_argument_tag<value_type>
operator()(const value_type& value) {
return accumulate_argument_tag<value_type>(value);
}
};static accumulate_tag accumulate;
// Global pipe operator which takes one argumenttemplate <typename
range_type, typename value_type>value_type
operator|(const range_type& range, const
accumulate_argument_tag<value_type>& argument_holder) {
return std::accumulate(std::begin(range), std::end(range),
argument_holder.value_);
}
// Global pipe operator which can accept 'accumulate' without any
parenthesis// (assuming that std::accumulate can be used without
arguments)template <typename range_type>typename
range_type::value_type
operator|(const range_type& range, const accumulate_tag&) {
return std::accumulate(std::begin(range), std::end(range),
range_type::value_type(0));
}

// Usage
std::vector<int> vec;for(size_t i = 0; i < 135; ++i)
vec.push_back(i);auto a = accumulate(vec, 0);auto b = vec |
accumulate(0);auto c = vec | accumulate;

/Viktor