С диапазонами Range v3, как объединить представления и действия в один конвейер? - PullRequest
9 голосов
/ 16 мая 2019

Я изучаю C ++ 20 диапазонов (используя Range-V3-VS2015 ).У меня есть этот код, который отлично работает:

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;

Однако я хотел бы объединить два конвейера, определяющих tmp1 и tmp2 в один конвейер.Это возможно?Я пробовал множество вещей, включая добавление view::move и view::copy в середине, но безрезультатно.

Ответы [ 2 ]

11 голосов
/ 16 мая 2019

Да, вы можете. Вам нужно использовать преобразование, чтобы материализовать представление в реальный контейнер для выполнения действий с ним. Я нашел новый фрагмент кода в основной ветке range-v3, представляющий range::v3::to<Container> для выполнения таких преобразований.

git blame предполагает, что Эрик начал работать над этим в этом году (2019), и это еще не задокументировано. Тем не менее, я нашел range-v3/test довольно хороший учебный материал о том, как используется библиотека:)

Сомневаюсь, что он доступен в ветке VS2015. Тем не менее, Visual 2017 уже может принять основную ветвь библиотеки.

#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;
}

Выходы:

abcz

что я считаю, это то, что вы ожидаете

4 голосов
/ 16 мая 2019

ranges::to - это то, что вы хотите.

Легко выполнить собственную замену.

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)) );
}

Не на уровне библиотеки (отсутствует ранний сбой, так каксамая большая проблема, и не поддерживает |), но вполне пригодна для использования.

, и тогда мы просто:

std::string r = to_container<std::string>( input | view::remove_if(not_alpha) | view::transform(::tolower) ) | action::sort |  action::unique;

Обратите внимание, что взятие адресов функций в std равно больше не рекомендуется (через @DavisHerring в комментарии выше)

Для обновления до |:

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{};

Что дает нам:

std::string r = input | view::remove_if(not_alpha) | view::transform(::tolower) | to_container<std::string> | action::sort |  action::unique;

По мере необходимости.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...