Reputation: 1129
I'm willing to do something as simple as this:
template <typename I, typename... In>
void bar() {
// Use I here
bar<In...>(); // Enable recursion
}
However, this leads to "ambiguous call to overloaded function". What makes me curious is that bellow code works:
template <typename T = void>
void foo() { }
template <int T, int... Tn>
void foo() {
foo<Tn...>();
}
Why is that? The following does works too:
void foobar() {}
template <typename I, typename... In>
void foobar(I i, In... in) {
foobar(in...);
}
So, whats the simplest way to achieve recursion, given this function signature WITHOUT USING ANY BRACED-INIT-LIST TECHNIQUES:
template <typename I, typename... In>
void bar();
Upvotes: 2
Views: 205
Reputation: 66210
You can solve in the same way foo()
solve: when the Tn...
list is empty, foo<>()
is called, so the foo()
version with a type template parameter (but with a default value) is called (the compiler match foo<>()
with foo<void>()
).
For bar()
you can switch integer and types.
You can add a terminal version that receive a non-type template parameter with a default value
template <int = 0>
void bar()
{ }
so when you call bar()
with a empty In...
type list, the compiler match the call bar<>()
with bar<0>()
.
--- EDIT ---
The OP ask
If
foo<>()
matches withfoo<void>()
, why doesntbar<>()
match withbar<void>()
(template <typename Dummy = void>
instead oftemplate <int = 0>)
? In other words, why does it have to be atemplate <int = 0>
(ofint
type)?
First of all, why foo()
works?
Because there are a foo()
variadic template function that receive one or more integers and a foo()
template that receive a single type (defaulted).
So, when you call foo<>
, it doesn't match the integer variadic version (because at least one integer in required) and match the type version (activating the void
default type).
Second: why bar()
doesn't works adding a version that receive a single (and defaulted) type?
Because you have a variadic template function that receive one or more types
template <typename I, typename... In>
void bar ()
{ bar<In...>(); }
so if you add a version that receive one type (defaulted)
template <typename = void>
void bar ()
{ }
you get into trouble the compiler: wich version choose when you call bar()
with the last type?
I mean: you call bar<int, long>()
and only the variadic version match.
But the variadic version call bar<long>()
.
The problem now is that both versions of bar()
(the variadic one and the one with a single type) match.
So the compiler give you an error.
The trick is to create a bar()
version with a single defaulted template parameter that can match the empty list call (foo<>()
) but doesn't clash with the type variadic version.
A possible solution is the int
one, but you can choose other types (char
, long
, unsigned long long
and others) or even a version based on a template-template defaulted parameter.
I mean... instead of
template <int = 0>
void bar ()
{ }
you can use
template <template <typename...> class = std::vector>
void bar()
{ }
This isn't a suggestion: I think the int = 0
is the simpler to write and understand. Just to show another possible way.
The point is adding a template that receive a single defaulted value but not a typename one.
Upvotes: 3