I have a Vector
class that does some math. Among other things, it has a mean()
function that calculates the mean of all values inside the vector. It uses a sum()
function that i added here just for completeness.
Vector
template <std::size_t N, typename T>
class Vector{
public:
// ...
T sum() const {
T ret{};
for (const auto &item : data) {
ret += item;
}
return ret;
}
template <typename U = T>
U mean() const {
return U(sum()) / N;
}
private:
std::array<T,N> data;
};
The mean()
function itself has a template parameter so that a caller of this function has the option to specify the type he wants his result in. For example, if Vector
is of type int
, the mean could be subject to precision loss if it is casted to the type of the Vector
, in this case int
:
Vector<3,int> vec{2,3,5};
int mean1 = vec.mean();
int mean2 = vec.mean<int>(); // same as mean1
float mean3 = vec.mean<float>();
As expected, the values are
3
3
3.333333f
This is all good. No problem here.
The problem i have is when i want to achieve the same with a free function (outside the class). My first, naive implementation was this
template <std::size_t N, class T>
T mean(const Vector<N, T> &other) {
return other.mean();
}
But when trying to calculate the float
mean, i'll have to always call this free function specifying both N
and T
, the template parameters.
Vector<3,int> vec{2,3,5};
float mean = mean<3, float>(vec);
// ^^^i want to get rid of this "3"
I understand that template argument deduction does not work in function prototypes... And that there is likely no way of deducting the parameter N
somehow without specifying it exactly. But maybe there is a completely unrelated workaround to remove the need of having to write out the N
value when calling the free function that i don't see?
Thanks to @Jarod42 and @HTNW i was able to hack it into a single function.
With class U = void
and std::conditional
it is possible to make the specification of U
optional for the caller.
template <class U = void, std::size_t N, typename T>
auto mean(const Vector<N, T> &v) {
return v.template mean<std::conditional_t<std::is_same_v<U, void>, T, U>>();
}
Example
Vector<3,int> v{2,3,5};
int mean1 = mean(v); // 3
int mean2 = mean<int>(v); // 3
float mean3 = mean<float>(v); // 3.333333f