一个 lambda 表达式不是函数指针! 它是编译器生成的类的实例!
然而,一个非捕获的 lambda 可以使用其 operator+
转换为函数指针。
这里有一个例子:
int main() {
auto lambda = [](int a) { return a; };
func ptr = +lambda;
return 0;
}
很遗憾,
operator+
在您的情况下甚至无法工作,因为它没有声明为constexpr,所以您不能在模板参数中使用它。
解决方案之一是使用自由函数……直到
N4487被接受之前,您不能指望将lambda作为模板参数传递。
另一个解决方案是创建您自己的functor而不是lambda:
struct LambdaType {
constexpr LambdaType() = default;
int operator()(int a) {
return run(a);
}
static int run(int a) {
return a;
}
};
int main() {
LambdaType lambda;
function<&LambdaType::run>(1);
return 0;
}
这个解决方案可能不太吸引人,但如果LambdaType
被隐藏在cpp文件中,它可能会很有用。
如果您的目标仅是让编译器能够内联您的代码,那么可以使用模板来传递lambda:
#include <iostream>
template <typename T>
int function(T foo, int a) {
return foo(a);
}
int main() {
int a;
std::cin >> a;
int b = function([](int a) { return a; }, a);
return b;
}
自从编译器知道每个实例的
T
类型,一个好的编译器应该能够将 lambda 优化掉。
使用 clang,第三个选项会生成如下汇编代码:
main:
pushq %rax
leaq 4(%rsp), %rsi
movl std::cin, %edi
callq std::basic_istream<char, std::char_traits<char> >::operator>>(int&)
movl 4(%rsp), %eax
addq $8, %rsp
retq
pushq %rax
movl std::__ioinit, %edi
callq std::ios_base::Init::Init()
movl std::ios_base::Init::~Init(), %edi
movl std::__ioinit, %esi
movl $__dso_handle, %edx
popq %rax
jmp __cxa_atexit
我使用了-std=c++14 -Ofast -march=native
作为标志。
function<test>(1);
不行。模板需要类型或整数常量作为参数。test
既不是类型也不是整数常量,lambda
也一样。 - DeiDeistd::function
呢?Lambda的类型只是一个带有重载operator()
的独特类。 - DeiDeistd::function
中,而用auto
声明时则不是。 - DeiDeistd::function
,而std::function
有一个相当明显的运行时开销。它在需要运行时类型测量时非常有用。说一个lambda是std::function
类型就像说字符串字面量是std::string
一样,它们并不是同一种东西。 - Guillaume Racicot