在 C++ 中,我们可以有一个递归可变参数模板函数。例如:
template<typename ...H>
void g(){}
template<typename H, typename ...T>
void g(H h,T ...t){
std::cout << h << "\t";
g<T...>(t...);
}
然而,这似乎无法使用 lambda 来完成。我主要关心的两个主要问题是:
- 如何建立基本案例。
- 如何使 lambda 既递归又可变。
我知道我可以使用递归 lambda,但看不到使其可变的方法。 这种类型的功能是否仅适用于更高级的语言,例如 Javascript?
编辑: 到目前为止,这是我想出的:
template<typename C,typename H, typename ...T>
std::function<void(C,H,T...)> f=[](auto&& self,H h,T ...t){
std::cout << h << "\t";
if(sizeof...(t)>0)
self(self,t...);
};
这里的第一个参数是 lambda 本身。 但是,主要问题是,为了调用此方法,我需要定义类型 C,但我不确定该怎么做(或者即使可能)。
编辑: 更简单的方法是:
auto f = [] (auto&& self, auto&& h,auto&&... t) {
std::cout << sizeof...(t) << "\n";
if( sizeof...(t)>0 ){
self(self,1);
}
};
int main()
{
f(f,1,2,3,4,5,6);
return 0;
}
但是报错如下:
main.cpp:55:13: error: use of ' [with auto:1 = &; auto:2 = int; auto:3 = {}]' before deduction of 'auto'
self(self,1);
^
最佳答案
C++17 用 Constexpr if 解决了这个问题:
#include <iostream>
auto f = [](auto&&... t){
auto f_impl = [](auto& self, auto&& h, auto&&... t) {
std::cout << sizeof...(t) << "\n";
if constexpr ( sizeof...(t)>0 ){
self(self,t...);
}
};
return f_impl(f_impl, t...);
};
int main() {
f(1,2,3,4,5,6);
}
我还冒昧地将第一个参数 (self
) 包装在“父”lambda 中。
使用 if(sizeof...(t))
作为守卫的问题在于,即使您不会在运行时使用不正确的参数调用 lambda,编译器仍然需要编译带有 sizeof...(t)==0
的表达式 self(self, t...)
失败。
constexpr if
通过在编译时进行检查来解决这个问题,甚至在检查结果为 false
时不编译 block 。在 C++17 之前,条件编译语义(不包括宏)只能使用 SFINAE 或模板特化来实现,这两者都不能仅使用 lambda 来完成。
关于C++ 递归可变参数 Lambda,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49495015/