2017-04-24 39 views
2

所以我最近看了关于C++这样的谈话: https://www.youtube.com/watch?v=mFUXNMfaciE范围V3扁平化序列

而且我是想出来很感兴趣。所以在一些玩具程序之后,我被困在如何正确地将载体矢量平铺成矢量。根据这里的文档:https://ericniebler.github.io/range-v3/这是可能的使用ranges::view::for_each。然而,我似乎无法让它工作。这是一些最小的代码。

#include <range/v3/all.hpp> 
#include <iostream> 
#include <vector> 

int main() 
{ 
    auto nums = std::vector<std::vector<int>>{ 
     {0, 1, 2, 3}, 
     {5, 6, 7, 8}, 
     {10, 20}, 
     {30}, 
     {55} 
    }; 

    auto filtered = nums 
     | ranges::view::for_each([](std::vector<int> num) { return ranges::yield_from(num); }) 
     | ranges::view::remove_if([](int i) { return i % 2 == 1; }) 
     | ranges::view::transform([](int i) { return std::to_string(i); }); 

    for (const auto i : filtered) 
    { 
     std::cout << i << std::endl; 
    } 
} 
+0

什么是不工作呢? – Galik

+0

@Galik以Main.cpp为例:main():: [with auto:1 = std :: vector ]'的实例化中的一长串编译错误: –

回答

3

范围-V3的错误信息往往是相当可怕的,以至于这一次实际上是最要好:

 
prog.cc: In lambda function: 
prog.cc:16:90: error: no match for call to '(const ranges::v3::yield_from_fn) (std::vector<int>&)' 
     | ranges::view::for_each([](std::vector<int> num) { return ranges::yield_from(num); }) 
                         ^
In file included from /opt/wandbox/range-v3/include/range/v3/view.hpp:38:0, 
       from /opt/wandbox/range-v3/include/range/v3/all.hpp:21, 
       from prog.cc:1: 
/opt/wandbox/range-v3/include/range/v3/view/for_each.hpp:133:17: note: candidate: template<class Rng, int _concept_requires_132, typename std::enable_if<((_concept_requires_132 == 43) || ranges::v3::concepts::models<ranges::v3::concepts::View, T>()), int>::type <anonymous> > Rng ranges::v3::yield_from_fn::operator()(Rng) const 
      Rng operator()(Rng rng) const 
       ^~~~~~~~ 

的人有位范围-V3的概念仿真知识层,这个“清楚地”指出,对yield_from的调用失败,因为您传递给它的参数的类型 - std::vector<int> - 不符合View概念。 012(0)

View概念描述了不拥有其元素的范围子集,因此具有所有操作 - 移动/复制构造/分配,开始,结束和默认构造 - 可在O(1)中计算。范围-V3中的范围组合algrebra仅适用于视图,以避免处理元素生命周期并提供可预测的性能。

yield_from拒绝std::vector是你试图传递因为它们不是视图,但是可以容易地提供由(1)在for_each取矢量作为左值,而不是通过值的观点,和(2)得到的那些view::all左值[DEMO]:

auto filtered = nums 
    | ranges::view::for_each([](std::vector<int>& num) { 
     return ranges::yield_from(ranges::view::all(num)); }) 
    | ranges::view::remove_if([](int i) { return i % 2 == 1; }) 
    | ranges::view::transform([](int i) { return std::to_string(i); }); 

但是,在这个简单的例子,压扁的范围内的元件的范围的成范围的元素已经在范围-V3特定目的视图:view::join。你可以使用它[DEMO]:

auto filtered = nums 
    | ranges::view::join 
    | ranges::view::remove_if([](int i) { return i % 2 == 1; }) 
    | ranges::view::transform([](int i) { return std::to_string(i); }); 
+0

令人惊叹。你能推荐一些我可以阅读的文档或文章,以便更好地了解所有这些工作原理吗? –

+0

另外为什么yield_from只能在非拥有范围上工作,而我可以将num不加改变为'ranges :: view_for_each()'? –

+1

视图接受* lvalue *容器并将其隐式转换为视图。这个想法是,一个左值可能会一直存在,直到你使用视图组合的结果,而一个右值可能会在完整表达式的末尾死去。 'yield_from'接受视图,但是* *不会*隐式地将左值转换为视图,因为它的典型用例在return语句中。这可以防止返回引用临时容器的视图,即,OP中的程序正在做什么。 – Casey