【发布时间】:2016-03-03 21:53:06
【问题描述】:
在 C++ 中使用 lambda 和函数对象而不是函数指针通常很有用。原因是 lambda 或函数对象的类型完全编码了被调用的内容(因此允许内联),而函数指针的类型仅编码签名。我有一个有趣的想法,即在使用泛型代码创建调用给定函数的 lambda 时它可能很有用。换句话说,给定指定函数的高阶函数返回调用它的 lambda。为了避免任何间接,必须使用函数指针非类型模板参数。问题是要指定这样一个非类型模板参数,你必须知道函数的签名。我无法绕过需要两次传递有问题的函数:一次是推断类型,一次是实际专注于函数。我最好的尝试是这样的:
template <class T>
struct makeLambdaHelper;
template <class R, class ... Args>
struct makeLambdaHelper<R(*)(Args...)>
{
template <void(*F)(Args...)>
static auto blah() {
return [] (Args && ... args) {
return F(std::forward<Args>(args)...);
};
}
};
要使用它,你会这样做:
void f(int, int) { std::cerr << "f\n"; };
...
auto lam = makeLambdaHelper<decltype(&f)>::blah<f>();
lam(0,0);
当 f 的类型作为模板参数传递给 makeLambdaHelper 时,首先推导出它的签名。然后结构体有一个静态函数,声明了一个非类型模板参数;所以我们通过 f 本身,并得到一个 lambda。像这样必须通过两次 f 非常难看;是否有可能做得更好,也许通过使用默认模板参数做一些聪明的事情?
【问题讨论】:
-
嗯...你的意思是像
std::bind? -
绑定某处是否有函数指针模板参数的特殊情况?如果没有,那么 lambda 内部会有一层间接,这对我没有帮助。我从这次谈话 (youtube.com/watch?v=zt7ThwVfap0) 中的理解是通常避免绑定。
-
bind 专门用于函数指针、成员函数指针、绑定到 shared_pointers 的成员函数等。为什么要避免绑定?它是标准库的一部分,因此能够使用您的标准兼容代码无法使用的魔术技巧。
-
如您所见,bind 在移除间接性方面并不成功,这与我的版本不同:goo.gl/hDk4mZ。此外,使用 bind 你必须指定笨重的 _1、_2 等。
-
并且您应该明确声明您这样做只是为了解决一些编译器使用 lambda 优化代码比使用仿函数的代码略好一些的问题。