2

我写了一个 kd-tree 模板,它的参数是一个自然数 K。

作为模板的一部分,我编写了以下函数来计算两点之间的距离(kd_point 是 std::array 的别名)

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++ 核心检查(发布)”,它给了我说的警告。是否有正确的方法来编写此例程以消除警告?

4

2 回答 2

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);
    }
  );
}
于 2017-11-18T14:07:44.370 回答
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;
}

请注意,与标准算法类似,此算法仅是标头,不会为您的代码带来任何库依赖性。

于 2017-11-20T06:49:58.500 回答