2017-06-21 42 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