2017-11-18 40 views
2

我寫了一個kd樹模板,它的參數是一個自然數K.如何消除'只使用常量表達式的索引到數組'警告?

作爲模板的一部分,我已經寫了下面的函數來計算兩個點(kd_point是一個別名之間的距離的std ::陣列)

template <unsigned K> 
float kd_tree<K>::DistanceSq(const kd_point &P, const kd_point &Q) 
{ 
    float Sum = 0; 

    for (unsigned i = 0; i < K; i++) 
     Sum += (P[i] - Q[i]) * (P[i] - Q[i]); 

    return Sum; 
} 

我已經變成 「啓用C++核心檢查(發行版)」 上,它給我說警告。有沒有正確的方法來編寫此例程以消除警告?

+0

基本上就意味着不使用原始'for'循環,使用範圍'for'循環。我不明白它是如何適用於你的情況的,但也許別人可以闡明。 – Rotem

+0

我知道如何編寫一個循環範圍來訪問每個kd點的每個元素。 如何編寫循環的範圍來訪問兩者以計算差異? –

回答

2

既然你在評論中提到你的kd_point的基於支持範圍的迭代(所以我假設可以返回迭代器),你可以在沒有原始循環的情況下重寫該函數。改爲使用標準庫中的命名算法:

template <unsigned K> 
float kd_tree<K>::DistanceSq(const kd_point &P, const kd_point &Q) 
{ 
    return std::inner_product(
    begin(P), end(P), begin(Q), 0.0f, std::plus<float>{}, 
    [](float pi, float qi) { 
     return (pi - qi)*(pi - qi); 
    } 
); 
} 

當然,標準庫將免於警告。如果(在這種情況下)通過命名操作替換原始循環的邊際好處並不吸引您,請考慮如果您使用支持C++ 17的編譯器回到此代碼,您將能夠幾乎不費吹灰之力並行化:

template <unsigned K> 
float kd_tree<K>::DistanceSq(const kd_point &P, const kd_point &Q) 
{ 
    return std::transform_reduce(std::execution::par, // Parallel execution enabled 
    begin(P), end(P), begin(Q), 0.0f, std::plus<float>{}, 
    [](float pi, float qi) { 
     return (pi - qi)*(pi - qi); 
    } 
); 
} 
+0

只是我還是C++在每個版本中都變得不太可讀? – Rotem

+0

@Rotem - 標準庫從一開始就有'std :: inner_product'。相信我,拉姆達使得它遠比它本來更具可讀性。並且指定的操作代替原始循環更容易「獲取」。我的意思是,是的,有一小部分的鍋爐板,但現在它有些明顯的內部產品操作,不是嗎? – StoryTeller

+0

我明白你的觀點。我對此有着複雜的感覺:) – Rotem

2

通過StoryTeller答案很可能是最合適的C++的方式來解決這個特殊的任務。

我想補充的是,在一般情況下,如果你想要不超過一個迭代,但在同時兩個序列,就可以使用「祕密超載boost::range::for_each」,接受兩個範圍:

#include <boost/range/algorithm_ext/for_each.hpp> 

template <unsigned K> 
float kd_tree<K>::DistanceSq(const kd_point &P, const kd_point &Q) 
{ 
    float Sum = 0; 

    boost::range::for_each(P, Q, [&Sum](float p, float q) 
    { 
     Sum += (p - q) * (p - q); 
    });   

    return Sum; 
} 

注與標準算法類似,此算法僅用於標題,不會爲您的代碼帶來任何庫依賴性。

相關問題