With Range v3 ranges, how to combine views and actions into a single pipeline?
Yes you can. You need to use a conversion to materialise the view into an actual container to perform actions on it. I found a new piece of code in the range-v3 master branch introducing range::v3::to<Container>
to perform such conversions.
git blame
suggests that Eric started working on it this year (2019) and it is not really documented yet. However, I find range-v3/test
pretty good learning material on how the library is used :)
I doubt that it is available in the VS2015 branch. However, Visual 2017 is already able to take the master branch of the library.
#include <string>
#include <iostream>
#include <cctype>
#include <range/v3/view/filter.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/action/sort.hpp>
#include <range/v3/action/unique.hpp>
#include <range/v3/range/conversion.hpp>
int main() {
using namespace ranges::v3;
std::string input = " 1a2a3Z4b5Z6cz ";
std::string result = input
| view::filter(::isalpha)
| view::transform(::tolower)
| to<std::string>
| action::sort
| action::unique;
std::cout << result << std::endl;
return 0;
}
Outputs:
abcz
which I believe is what you expect
ranges::to
is what you want.
Rolling your own semi-replacement is easy.
template<class C, class R>
C to_container( R&& r ) {
using std::begin; using std::end;
return C( begin(std::forward<R>(r)), end(std::forward<R>(r)) );
}
Not library-strength (lacks early failure as the biggest problem, and does not support |
) but quite usable.
and then we just:
std::string r = to_container<std::string>( input | view::remove_if(not_alpha) | view::transform(::tolower) ) | action::sort | action::unique;
Note that taking addresses of functions in std
is no longer advised (via @DavisHerring in a comment above)
To upgrade to |
:
template<class C>
struct to_container_t {
template<class R>
C operator()( R&& r )const {
using std::begin; using std::end;
return C( begin(std::forward<R>(r)), end(std::forward<R>(r)) );
}
template<class R>
friend C operator|( R&& r, to_container_t self ){
return self( std::forward<R>(r) );
}
};
template<class C>
constexpr to_container_t<C> to_container{};
Which gives us:
std::string r = input | view::remove_if(not_alpha) | view::transform(::tolower) | to_container<std::string> | action::sort | action::unique;
As required.