如何正确指定递归模板 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...>();
}
但与使用递归相比,折叠表达式(已在其他答案中给出)在您的情况下似乎是一种更有效的方法。
您的第一次尝试没有成功,因为声明 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';
}()), ...);
}
我想解压可变参数模板参数包。由于该函数需要访问对象的私有成员,所以我决定将其编写为成员函数。据我了解,根据标准,必须在与封闭 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...>();
}
但与使用递归相比,折叠表达式(已在其他答案中给出)在您的情况下似乎是一种更有效的方法。
您的第一次尝试没有成功,因为声明 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';
}()), ...);
}