Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

With Range v3 ranges, how to combine views and actions into a single pipeline?

I'm learning C++20 ranges (using Range-V3-VS2015). I have this code that works fine:

string clean;
auto tmp1 = input | view::remove_if(not_alpha) | view::transform(::tolower);
std::copy(tmp1.begin(), tmp1.end(), std::back_inserter(clean));
auto tmp2 = clean |= action::sort |  action::unique;

However, I would like to combine the two pipelines defining tmp1 and tmp2 into a single pipeline. Is that possible? I've tried numerous things, including adding view::move and view::copy in the middle, to no avail.

like image 990
busfahrer Avatar asked May 16 '19 18:05

busfahrer


People also ask

Is range v3 header only?

Disclaimers. The library used in the code examples is not really the C++20 ranges, it's the ranges-v3 open-source library from Eric Niebler, which is the basis of the proposal to add ranges to the C++. It's a header-only library compatible with C++11/14/17.

What is Range v3?

Range v3 is a generic library that augments the existing standard library with facilities for working with ranges. A range can be loosely thought of a pair of iterators, although they need not be implemented that way.

What are C++ ranges?

Range - Ranges are an abstraction that allows a C++ program to operate on elements of data structures uniformly. On minimum a range contains defines begin() and end() to elements. There are several different types of ranges: containers, views, sized ranges, Container - It's a range that owns the elements.


2 Answers

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

like image 126
CygnusX1 Avatar answered Sep 25 '22 23:09

CygnusX1


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.

like image 34
Yakk - Adam Nevraumont Avatar answered Sep 26 '22 23:09

Yakk - Adam Nevraumont