Reputation: 193
I want to make a function that accepts types and call itself again by looping or recursion.
What I had already tried was below, but it only called the base function (Called base function with AModule
class and didn't call the function with BModule.
class AModule {
};
class BModule {
};
auto main() -> int {
init<AModule, BModule>()
return 0;
}
template<typename Module>
void init() {
// BASE FUNCTION
// Do something
}
template<typename... Modules>
void init() {
(init<Modules>(), ...)
}
Upvotes: 0
Views: 67
Reputation: 66230
In the code in your example you're using template-folding, a new C++17 feature that permit you to avoid recursion.
But, to avoid a name collision, I suggest to call the base version in a different way; say do_something()
template<typename Module>
void do_something() {
// BASE FUNCTION
// Do something
}
template<typename... Modules>
void init() {
(do_something<Modules>(), ...);
}
If you really want use recursive way, you can do something as follows
template <int = 0>
void init ()
{
// stop recursion; do nothing
}
template <typename Head, typename ... Tail>
void init ()
{
// do something with Head
// recursively call init()
init<Tail...>();
}
The trick is that calling init<Tail...>();
, until Tail...
isn't empty is called the Head
/Tail...
recursive version.
When Tail...
is empty, init<Tail...>()
is init<>()
so the Head
/Tail...
version doesn't matches anymore (there isn't a Head
) but matches the int = 0
version; so init<>()
become init<0>()
and the ground-do-nothing case stops recursion.
Upvotes: 3
Reputation: 19771
In your code (once syntax errors were fixed), both init()
calls were valid for 1 template parameter, so the call was ambiguous. By making the multi-init call require at least 2 parameters, that ambiguity is removed.
// bogus type that just prints an error message including the type it is parameterized with
template<typename T>
struct printer;
template<typename Module>
void init() {
printer<Module>{}; // this is an error just to show you that it's getting called with both types
}
// only call this if it's called with 2 or more types, otherwise just use the other init()
template<typename T1, typename T2, typename... Modules>
void init() {
init<T1>();
init<T2>();
(init<Modules>(), ...);
}
class AModule {
};
class BModule {
};
auto main() -> int {
init<AModule, BModule>();
return 0;
}
live: https://godbolt.org/z/D-eh2G
Upvotes: 1