I was writing some geometry-related code again and had a closer look at my function supposed to compute the Euclidean distance between two points (N-dimensional points by the way, hence the N
template parameter). Here is a simplified version:
template<std::size_t N, typename T>
auto distance(const Point<N, T>& lhs, const Point<N, T>& rhs)
-> T
{
T res{};
for (std::size_t i = 0 ; i < N ; ++i)
{
auto tmp = std::abs(lhs[i] - rhs[i]);
res += tmp * tmp;
}
return std::sqrt(res);
}
So far, so good. However, one very common operation is to compare the distances. Generally speaking, when comparing the distances, the sqrt
is optimized away and the sum of the squares is compared instead of the distance itself. Therefore, I tried to create some kind of expression template to represent the distance between two points, so that users will benefit from both the ease of use and the "get rid of sqrt
optimization" when comparing distances. Basically, the call of sqrt
is not done until the exact value of the distance is needed. Here is the class:
template<typename T>
struct DistanceExpression
{
explicit constexpr DistanceExpression(T data):
_data(data)
{}
operator T() const
{
return std::sqrt(_data);
}
bool operator==(const DistanceExpression& other) const
{
return _data == other._data;
}
bool operator!=(const DistanceExpression& other) const
{
return !(*this == other);
}
private:
T _data;
};
My new distance
function is implemented as such:
template<std::size_t N, typename T>
auto distance(const Point<N, T>& lhs, const Point<N, T>& rhs)
-> DistanceExpression<T>
{
T res{};
for (std::size_t i = 0 ; i < N ; ++i)
{
auto tmp = std::abs(lhs[i] - rhs[i]);
res += tmp * tmp;
}
return DistanceExpression<T>{res};
}
Here is a minimal working code at Coliru. Is such a design reasonable or is it overkill to elegantly solve this problem?