In working on another problem, one component I needed was to calculate the centroid of a collection of complex objects. The well-known way to calculate this is to simply average the real and imaginary parts. To accommodate either std::complex<double>
or std::complex<float>
, I have created the following code as a template. Everything works as expected.
centroid.cpp
#include <iostream>
#include <complex>
#include <vector>
#include <numeric>
template<class ComplexIterator>
typename ComplexIterator::value_type centroid(ComplexIterator a, ComplexIterator b) {
return std::accumulate(a, b, typename ComplexIterator::value_type{0})
/ typename ComplexIterator::value_type{b-a};
}
int main() {
std::vector<std::complex<float>> points{ {4,5}, {30,6}, {20,25} };
std::cout << centroid(points.begin(), points.end()) << "\n";
}
Sample output:
(18, 12)
My questions
- The compiler rightly warns that in the calculation of the denominator in the template, there is a narrowing conversion. I can't think of a way to elegantly handle that. Should I just ignore it?
- If given an empty set, the code returns a value of
(-nan, -nan)
which works for me, but for general use, should I throw an exception instead? - Should I use
std::enable_if
or C++20requires
to constrain the function to require only floating point numbers? - I thought about calling it
average
because technically, it would happily compute the average of, say, astd::vector<float>
but for my purposes,centroid
seemed apt. What do you think of that choice?
Any other ways to improve this would be good as well.