Calculate the centroid of a collection of complex numbers 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&lt;double&gt; or std::complex&lt;float&gt;, I have created the following code as a template.  Everything works as expected.
centroid.cpp
#include &lt;iostream&gt;
#include &lt;complex&gt;
#include &lt;vector&gt;
#include &lt;numeric&gt;

template&lt;class ComplexIterator&gt; 
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&lt;std::complex&lt;float&gt;&gt; points{ {4,5}, {30,6}, {20,25} };
    std::cout &lt;&lt; centroid(points.begin(), points.end()) &lt;&lt; &quot;\n&quot;;
}

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++20 requires 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, a std::vector&lt;float&gt; 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.
Taking all of the suggestions from the other reviews, I think it's quite improved so I wanted to thank the reviewers and show the final version:
#include &lt;iostream&gt;
#include &lt;complex&gt;
#include &lt;vector&gt;
#include &lt;numeric&gt;
#include &lt;concepts&gt;
#include &lt;ranges&gt;
#include &lt;array&gt;
#include &lt;iterator&gt;

template&lt;typename T&gt; 
concept ComplexOrFloat = std::floating_point&lt;T&gt;
    || std::floating_point&lt;typename T::value_type&gt;;

template&lt;typename R&gt; 
requires std::ranges::range&lt;R&gt; 
    &amp;&amp; ComplexOrFloat&lt;std::ranges::range_value_t&lt;R&gt;&gt;
constexpr std::ranges::range_value_t&lt;R&gt; average(R range) {
    if (std::ranges::size(range) == 0) 
        throw std::domain_error(&quot;Cannot take average of zero-length range&quot;);
    using T = std::ranges::range_value_t&lt;R&gt;;
    return std::accumulate(std::ranges::begin(range), std::ranges::end(range), T{0}) 
        / (T)(std::ranges::size(range));
}

int main() {
    using namespace std::complex_literals;
    constexpr std::array&lt;std::complex&lt;double&gt;,3&gt; points{{ {4,5}, {30,6}, {20,25} }};
    std::cout &lt;&lt; average(std::views::all(points)) &lt;&lt; &quot;\n&quot;;

    constexpr std::array&lt;std::complex&lt;double&gt;,3&gt; points2{
        {  24.0 + 7.0i, 22.0 + 9.0i, 8.0 + 20.0i }
    };
    std::cout &lt;&lt; average(std::views::all(points2)) &lt;&lt; &quot;\n&quot;;

    constexpr double numbers[]{1, -2, 3, 7, -8};
    std::cout &lt;&lt; average(std::views::all(numbers)) &lt;&lt; &quot;\n&quot;;

    const std::vector&lt;float&gt; numbers2{-7, -2, 3, 7, -8};
    std::cout &lt;&lt; average(std::views::all(numbers2)) &lt;&lt; &quot;\n&quot;;

    const std::vector&lt;float&gt; mt{};
    try {
        std::cout &lt;&lt; average(std::views::all(mt)) &lt;&lt; &quot;\n&quot;;
    } catch (std::domain_error&amp; err) {
        std::cerr &lt;&lt; &quot;ERROR: &quot; &lt;&lt; err.what() &lt;&lt; &quot;\n&quot;;
    }

#if 0
    int intnumbers[]{1, -2, 3, 7, -8};
    // won't compile because an `int` is not floating point or complex floating point
    std::cout &lt;&lt; average(std::views::all(intnumbers)) &lt;&lt; &quot;\n&quot;;
#endif
}

I'm using C++20 concepts to avoid trying to take an average of a range of ints and returning an int.