Nujufas
Nujufas

Reputation: 782

Variadic Templates - Recursive function - Last variadic member

I have the following code with a variadic template copied from: https://www.youtube.com/watch?v=iWvcoIKSaoc @41:30

auto sum() { return 0; }

template<typename Head, typename... Tail>
auto sum(Head head, Tail... tail)
{
    return head+sum(tail...);
}

int main() {
    cout<< sum(1,2.4) << endl;
    //cout<< sum("hello ", "world") << endl;
    return 0;
}

I have two questions: 1. The sum() function is required here so that I can have a return value for a void passed in when processing the last variadic member - Is it possible to avoid writing this sum() function and have the same functionality?

  1. Returning a integer '0' from the sum() function restricts the entire template to be used by integers - Can I extend the same template to concatenate strings?

Thank You

Upvotes: 4

Views: 193

Answers (3)

  1. The sum() function is required here so that I can have a return value for a void passed in when processing the last variadic member - Is it possible to avoid writing this sum() function and have the same functionality?

Every recursion needs a stop condition. In the typical use of recursion with variadic templates (such as in this code), the stop condition is a different overload of the primary template. So you cannot get rid of this entirely.

You can of course replace the stop condition with a different one. Perhaps this one, which will also work for summing things which are not default-constructible:

template <class T>
auto sum(T last) { return last; }

Of course, there are other approaches to this than recursive variadic templates; such approaches may not need a stop condition.

  1. Returning a integer '0' from the sum() function restricts the entire template to be used by integers - Can I extend the same template to concatenate strings?

No, because the non-template function has no knowledge of which type the previous recursive invocations were dealing with. This can be solved by using the "last item" stop condition I suggested above.

Upvotes: 1

KostasRim
KostasRim

Reputation: 2053

To complement @GuillaumeRacicot answer I prefer to end a recursion with if constexpr which is a c++17 feature.

template<typename Head, typename Second, typename... Tail>
auto sum(Head head, Second second, Tail... tail)
{ 
    if constexpr(sizeof...(tail) > 0)
      return head + sum(second, tail...);
    return head + second;
}

You can also consider fold expressions:

template<typename ...Pack>
auto sum(Pack... args) {
    return (args + ...);
}

Upvotes: 6

Guillaume Racicot
Guillaume Racicot

Reputation: 41760

The trick is to never allow empty sum() calls, and treat the sum(last) as the last recursion:

template<typename Last>
auto sum(Last last) {
    return last;
}

template<typename Head, typename Second, typename... Tail>
auto sum(Head head, Second second, Tail... tail)
{
    return head + sum(second, tail...);
}

int main() {
    cout<< sum(1,2.4) << endl;
    cout<< sum("hello ", "world") << endl;
    return 0;
}

Live example

Upvotes: 3

Related Questions