使用 Range v3 范围,如何将视图和操作组合到一个管道中?
With Range v3 ranges, how to combine views and actions into a single pipeline?
我正在学习 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
,但无济于事。
是的,你可以。您需要使用转换将视图 material 化为实际容器以对其执行操作。我在 range-v3 master 分支中发现了一段新代码,介绍了 range::v3::to<Container>
来执行此类转换。
git blame
建议 Eric 今年(2019 年)开始研究它,但尚未真正记录在案。但是,我发现 range-v3/test
很好地学习 material 如何使用库 :)
我怀疑它在 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
我相信这就是您所期望的
ranges::to
就是你想要的
自己滚动 semi-replacement 很容易。
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)) );
}
不是library-strength(缺乏早期失败是最大的问题,并且不支持|
)但非常有用。
然后我们只是:
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;
根据需要。
我正在学习 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
,但无济于事。
是的,你可以。您需要使用转换将视图 material 化为实际容器以对其执行操作。我在 range-v3 master 分支中发现了一段新代码,介绍了 range::v3::to<Container>
来执行此类转换。
git blame
建议 Eric 今年(2019 年)开始研究它,但尚未真正记录在案。但是,我发现 range-v3/test
很好地学习 material 如何使用库 :)
我怀疑它在 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
我相信这就是您所期望的
ranges::to
就是你想要的
自己滚动 semi-replacement 很容易。
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)) );
}
不是library-strength(缺乏早期失败是最大的问题,并且不支持|
)但非常有用。
然后我们只是:
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;
根据需要。