【问题标题】:With Range v3 ranges, how to combine views and actions into a single pipeline?使用 Range v3 范围,如何将视图和操作组合到单个管道中?
【发布时间】:2019-10-04 01:56:50
【问题描述】:

我正在学习 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;

但是,我想将定义 tmp1tmp2 的两个管道组合成一个管道。那可能吗?我尝试了很多方法,包括在中间添加view::moveview::copy,均无济于事。

【问题讨论】:

  • 你不应该拿标准库函数的地址anymore;使用 lambda 调用它们。 (是的,这对于 C++ 不会重载的 C 库函数来说有点傻。)
  • 为什么要将它们合并到一个管道中?不应该是相反的——将这两条管道分成不同的操作吗?

标签: c++ stl std range-v3


【解决方案1】:

是的,你可以。您需要使用转换将视图具体化为实际容器以对其执行操作。我在 range-v3 master 分支中发现了一段新代码,引入了range::v3::to<Container> 来执行此类转换。

git blame 建议 Eric 今年(2019 年)开始研究它,但尚未真正记录在案。不过,我发现range-v3/test 是关于如何使用该库的很好的学习材料 :)

我怀疑它在 VS2015 分支中是否可用。但是,Visual 2017 已经能够采用该库的 master 分支。

#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

我相信这是你所期望的

【讨论】:

  • 来这里说这个。 +1。
  • 谢谢!作为背景和我更深入的理解,为什么这对 view::copy 或 view::move 都不起作用?
【解决方案2】:

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 中获取函数的地址是no longer advised(通过上面评论中的@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;

根据需要。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-07-13
    • 1970-01-01
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多