I want to unpack a variadic template parameter pack. As the function requires access to private members of the object, I decided to write it as a member function. To my understanding, according to the standard, a template function has to be specified in the same namespace as the enclosing class, I tried to separate declaration and definition. As I result I only received lookup errors.
Below is a short recreation of what I'm trying to do:
class Container{
private:
//My first try
template<typename... Ts>
void foo();
//Second try
template<> foo();
template<typename T, typename... Ts>
void foo();
}
template<> void Container:foo(){}
template<typename T, typename... Ts>
void Container::foo(){
foo<Ts...>();
}
What am I supposed to write instead of the commented parts, or is there a more general mistake in how I'm trying this?
I already looked at questions like recursive variadic template to print out the contents of a parameter pack, but none of them used a member function, so it didn't really help sadly.
Also, this should just do nothing in case of an empty parameter list. Which is why the following didn't work.
template<typename T, typename... Ts>
void foo(){
if constexpr (sizeof...(Ts)){
foo<Ts...>();
}
}
About the error messages:
For try 1 -
Container::foo() does not match any template declaration
For try 2 -
explicit specialization in non-namespace scope class Container
CodePudding user response:
In C 20 you can use template lambda to extract the first template parameter like this:
class Container {
private:
template<typename... Ts>
void foo();
};
template<typename... Ts>
void Container::foo() {
if constexpr (sizeof...(Ts))
[this]<typename /*First*/, typename... Rest> {
foo<Rest...>();
}.template operator()<Ts...>();
}
But compared to using recursion, fold expression (which already given in other answers) seems to be a more efficient approach in your case.
CodePudding user response:
Your first try didn't work because the declaration template<typename... Ts> void foo();
has to be matched with a declaration that looks the same, not template<typename T, typename... Ts> void foo() { // ...
, which has different template parameters.
In C 17, it is pretty simple to "do something" for each thing in a parameter pack using fold expressions:
class Container {
private:
template<typename... Ts>
void foo();
};
template<typename... Ts>
void Container::foo() {
// Fold over comma which calls and discards the result of a lambda
(([&]{
// Use `Ts` here. For example:
std::cout << typeid(Ts).name() << '\n';
}()), ...);
}