You've almost figured out the answer for yourself. Pay attention to this line:
sum += Sum(x);
The type of sum
, which is what we’re after, must be something compatible for assignment with the result of our recursive call to Sum
. One such type, given your requirements, is certainly the result type of the call.
We don't have to rely on just a fuzzy feeling though. Meta-programming is, after all, programming. You may not have realised it, but your problem is one of well-founded recursion which means that the principle of induction can guide us towards an answer.
in the base case, we have a numerical, non-vector element_type element;
, meaning our result type is… element_type
. you've in fact already managed this step, it’s the first overload:
template<typename T>
T Sum(T element);
in the recursive case we have:
std::vector<element_type> vec;
the induction hypothesis, i.e.:
// given
element_type element;
// we know the following is well-formed and a numerical type
using recursive_result_type = decltype( Sum(element) );
Since the vector elements have type element_type
, the induction hypothesis gives us that the result of calling Sum
on them has all the properties we want. (The justification for our +=
intuition is rooted here.) We have our anser: we use recursive_result_type
as-is.
Now as it turns out that second overload cannot just be written e.g. like so:
// doesn't behave as expected
template<typename Element>
auto Sum(std::vector<Element> const& vec) -> decltype( Sum(vec.front()) );
The reason being that the current Sum
overload being declared is not in scope in the return type (even though it is in the definition body). One way to work around that is to rely on class scope, which is more accommodating:
// defining a functor type with operator() overloads
// would work just as well
struct SumImpl {
template<typename Element>
static T apply(Element element)
{ return element; }
template<typename Element>
static auto apply(std::vector<Element> const& vec)
-> decltype( apply(vec.front()) )
{
using result_type = decltype( apply(vec.front()) );
result_type sum = 0;
for(auto const& element: vec) {
sum += apply(element);
}
return sum;
}
};
template<typename Arg>
using sum_result_t = decltype( SumImpl::apply(std::declval<Arg const&>()) );
template<typename Arg>
sum_result_t<Arg> Sum(Arg const& arg)
{ return SumImpl::apply(arg); }
Coliru demo