2017-06-21 46 views
3

出于某种原因,下面列表中的代码会导致clang ++和g ++使用100%的CPU,并填充内存,直到系统挂起。范围的递归函数(从范围-v3)导致编译分歧:为什么?

请注意,这是一个演讲的玩具例子。我知道accumulatetransform是这样做的标准方法,但是这个代码是推理链中的一个中间点。

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

using namespace ranges; 

template <typename F, typename R, typename T> 
T rec_map_sum(F f, R r, T tally) { 
    if (ranges::begin(r) == ranges::end(r)) 
    return tally; 
    else { 
    auto r_head = *ranges::begin(r); 
    auto r_tail = r | view::drop(1); 
    return rec_map_sum(f, r_tail, tally + f(r_head)); 

    // this also crashes: 
    // return rec_map_sum(f, r[{1, end}], tally + f(r_head)); 
    } 
} 

int main() { 
    std::cout << rec_map_sum([](int x) { return x * x; }, view::iota(0, 10), 0) 
      << std::endl; 

    return 0; 
} 

rec_map_sum该功能是指执行一个递归采用一个范围内的整数和一元函数的,应用功能逐元素的范围内,并产生所映射的元素的总和。我有两个问题:(1)发散行为的原因是什么,(2)我应该如何制作和传递尾部视图,以便编译不会崩溃?

+4

你是怎样处理递归的结束? – Jarod42

+0

@ Jarod42噢我的,我因为编译器崩溃而忘了写条件返回。我会修改它。非常感谢您快速指出我的失态。 – Timtro

+1

你的第二个分支仍然强制实例化无限数量的函数'rec_map_sum'。 – Jarod42

回答

2

问题由Jarod42指出,但解决方案非常简单。你需要一个类型擦除视图,可以采取任何范围。幸运的是,such a thing exists。你的代码更改为:

template <typename F, typename R, typename T> 
T rec_map_sum(F f, R r, T tally) { 
    auto r2 = any_view<T>{r}; 
    if (ranges::begin(r2) == ranges::end(r2)) 
    return tally; 
    else { 
    auto r_head = *ranges::begin(r2); 
    auto r_tail = r2 | view::drop(1); 
    return rec_map_sum(f, r_tail, tally + f(r_head)); 
    } 
} 

这将打印285