是否有std::函数类型或类似于带有auto参数的lambda
Is there a std::function type or similar for lambda with auto parameter?
当我将lambda赋值给显式类型变量时(例如,当它是递归的时,为了捕获函数本身),我使用std::function
。
以这个愚蠢的"位计数"函数为例:
std::function<int(int)> f;
f = [&f](int x){ return x ? f(x/2)+1 : 0; };
如果我们使用auto参数泛化x
,就像c++ 14 generic lambda中介绍的那样呢?
std::function<int(???)> f;
f = [&f](auto x){ return x ? f(x/2)+1 : 0; };
显然,我不能把auto
放在function
类型参数中。
是否有可能定义一个泛型的函数类,足以覆盖上面的确切情况,但仍然使用lambda函数定义?
(不要过于一般化,只接受一个auto参数并硬编码返回值。)该用例将适用于上面的场景:通过引用捕获函数本身以进行递归调用。
您可以通过将其作为参数传递给自身来创建调用自身的lambda:
auto f = [](auto self, auto x) -> int {
return x ? self(self, x / 2) + 1 : 0;
};
std::cout << f(f, 10);
然后你可以在另一个lambda中捕获这个lambda,所以你不必担心将它传递给它自己:
auto f2 = [&f](auto x) {
return f(f, x);
};
std::cout << f2(10);
这是一个快速的基于y组合子的递归引擎:
template<class F>
struct recursive_t {
F f;
// note Self must be an lvalue reference. Things get
// strange if it is an rvalue:
// invoke makes recursive ADL work a touch better.
template<class Self, class...Args>
friend auto invoke( Self& self, Args&&...args )
-> decltype( self.f( self, std::declval<Args>()... ) )
{
return self.f( self, std::forward<Args>(args)... );
}
// calculate return type using `invoke` above:
template<class Self, class...Args>
using R = decltype( invoke( std::declval<Self>(), std::declval<Args>()... ) );
template<class...Args>
R<recursive_t&, Args...> operator()(Args&&...args)
{
return invoke( *this, std::forward<Args>(args)... );
}
template<class...Args>
R<recursive_t const&, Args...> operator()(Args&&...args)const
{
return invoke( *this, std::forward<Args>(args)... );
}
};
template<class F>
recursive_t< std::decay_t<F> > recurse( F&& f )
{
return {std::forward<F>(f)};
}
现在你可以这样做:
auto f = recurse( [](auto&& f, auto x){ return x ? f(x/2)+1 : 0; } );
,你得到一个递归lambda,它没有&
捕获(这限制了它在当前范围内的使用)。
通过引用捕获std::function
意味着lambda的生命周期是当前作用域,并且每个递归调用都需要越过类型擦除(阻塞任何可能的优化,例如尾递归,越过递归调用)。其他类似的解决方案也是如此。
需要使用recursive_t
而不是使用lambda,因为lambda不能在自己内部命名自己。
生活例子。
基于lambda的版本在实现上稍微简单一些。注意,对于可变的和不可变的lambdas,您需要一个不同的类型函数:
template<class F>
auto recurse( F&& f ) {
return [f=std::forward<F>(f)](auto&&...args){
return f(f, decltype(args)(args)...);
};
};
recursive_t
的工作方式如下:
auto fib = recurse( [](auto&& fib, int x){ if (x<2) return 1; return fib(x-1)+fib(x-2); } );
lambda版本的工作方式如下:
auto fib = recurse( [](auto&& self, int x){ if (x<2) return 1; return self(self, x-1)+self(self,x-2); } );
我个人觉得更尴尬。
描述recurse
的类型也比较困难。对于recursive_t
版本,recurse
的类型为:
((A->B)->A->B)->(A->B)
有点别扭,但这是一个有限类型。
lambda版本更棘手。recursive
的函数实参类型为:
F:= F->A->B
是一个烦人的无穷大,然后recurse
的类型是
F->A->(A->B)
继承了无穷大
无论如何,recurse
返回值可以存储在普通的std::function
中,或者不存储在任何类型擦除的容器中。
- 将函数参数类型声明为 auto
- 使用constexpr + auto作为返回和参数类型的奇怪类型推导
- C++/11 auto 关键字是在更有效时推导参数进行按引用传递,还是始终按值传递?
- C++17.处理使用 auto 相关的模板参数.代码排序困难
- 无法使用 auto 来参数化true_type来检测 T::value()
- 将 auto 与生成元组的可变参数模板一起使用
- 使用"auto"的部分专用模板推断失败的模板参数推断
- 无法通过 std::ref() 使用 auto& 参数调用 std::invoke()
- Hana::Tuple to Auto && ...参数
- 省略C++可变参数 lambda 中的"auto"关键字?
- 在 QGraphicsScene 中拖动 QPixmap:如何避免 lambda 参数中不允许'auto'
- 在模板参数中使用 auto:一些使用示例和..如何使其与恒定大小的 C 数组一起使用
- 如何用'auto'单词推导出哪种类型的参数编写函数?
- 将 auto 作为参数传递(用于指向对象的指针)
- 如何处理"警告:在参数声明中使用'auto'仅适用于 -fconcepts"
- 是在模板模板参数的情况下,是由DECTTYPE(AUTO)推出的参考非类型模板参数
- lambda 中的跨平台"auto"关键字用法:integral_constant作为函数参数
- 使用auto参数从lambdas返回值
- 使用auto参数munmap_chunk()返回auto的函数:无效指针
- 是否有std::函数类型或类似于带有auto参数的lambda