如何正确指定递归模板 class 成员函数?

How to properly specify a recursive template class member function?

我想解压可变参数模板参数包。由于该函数需要访问对象的私有成员,所以我决定将其编写为成员函数。据我了解,根据标准,必须在与封闭 class 相同的命名空间中指定模板函数,我试图将声明和定义分开。结果我只收到查找错误。

下面是我正在尝试做的事情的简短再现:

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...>();
}

我应该写什么来代替评论部分,或者我的尝试方式是否存在更普遍的错误?

我已经看过 recursive variadic template to print out the contents of a parameter pack 之类的问题,但是其中 none 使用了成员函数,所以它并没有真正起到帮助。

此外,如果参数列表为空,这应该什么也不做。这就是以下内容不起作用的原因。

template<typename T, typename... Ts>
void foo(){
    if constexpr (sizeof...(Ts)){
        foo<Ts...>();
    }
}

关于错误信息:

对于尝试 1 -

Container::foo() does not match any template declaration

尝试 2 -

explicit specialization in non-namespace scope class Container

在 C++20 中,您可以使用模板 lambda 提取第一个模板参数,如下所示:

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...>();
}

Demo.

但与使用递归相比,折叠表达式(已在其他答案中给出)在您的情况下似乎是一种更有效的方法。

您的第一次尝试没有成功,因为声明 template<typename... Ts> void foo(); 必须与看起来相同的声明相匹配,而不是 template<typename T, typename... Ts> void foo() { // ...,后者具有不同的模板参数。

在 C++17 中,使用 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';
    }()), ...);
}