我开始使用C ++ 11 lambdas开发应用程序,并且需要将某些类型转换为函数指针。这在GCC 4.6.0中完美运行:
void (* test)() = []()
{
puts("Test!");
};
test();
我的问题是当我需要在lambda中使用函数或方法局部变量时:
const char * text = "test!";
void (* test)() = [&]()
{
puts(text);
};
test();
G ++ 4.6.0给出了强制转换错误代码:
main.cpp: In function 'void init(int)':
main.cpp:10:2: error: cannot convert 'main(int argc, char ** argv)::<lambda()>' to 'void (*)()' in initialization
如果使用自动,则可以正常使用:
const char * text = "Test!";
auto test = [&]()
{
puts(text);
};
test();
我的问题是:如何使用 [&amp;] 为lambda创建一个类型?在我的情况下,我不能使用STL std :: function (因为我的程序不使用C ++ RTTI和EXCEPTIONS运行时),并且它有一个简单的函数实现来解决这个问题?
答案 0 :(得分:10)
我不能使用STL std :: function(因为我的程序不使用C ++ RTTI和EXCEPTIONS运行时)
然后,您可能需要将自己的等效内容编写为std::function
。
std::function
的类型擦除的常规实现不需要RTTI来实现其大多数功能;它通过常规虚函数调用工作。所以编写自己的版本是可行的。
实际上,std::function
中 RTTI所需的唯一内容是target_type
和target
函数,它们不是世界上最有用的函数。您可以在不调用这些函数的情况下使用std::function
,假设您正在使用的实现不需要RTTI用于其常规业务。
通常,当您禁用异常处理时,程序会在遇到throw
语句时关闭并出错。而且,由于std::function
发出的大多数异常都不是你能够从中恢复的东西(调用空function
,内存耗尽等),你可能只需按原样使用std::function
。
答案 1 :(得分:9)
只有没有捕获的lambda才能转换为函数指针。这是lambdas的扩展,仅适用于这种特殊情况[*]。通常,lambdas是函数对象,您不能将函数对象转换为函数。
具有状态(捕获)的lambda的替代方法是使用std::function
而不是普通的函数指针。
[*]:如果保持状态的lambda可以转换为函数指针,那么状态将保持在哪里? (注意,这个特殊的lambda可能有多个实例,每个实例都有自己需要单独维护的状态)
答案 2 :(得分:6)
正如已经提到的,只有没有捕获任何内容的lambda才能转换为函数指针。
如果您不想使用或编写像std :: function之类的东西,那么另一种选择是将参数传递给您将以其他方式捕获的内容。您甚至可以创建一个结构来保存它们。
#include <iostream>
struct captures { int x; };
int (*func)(captures *c) = [](captures *c){ return c->x; };
int main() {
captures c = {10};
std::cout << func(&c) << '\n';
}
另一种方法是使用不需要捕获的global / static / thread_local / constexpr变量。
答案 3 :(得分:2)
您可以使用std::function
,它不需要任何“运行时”。否则,look here for a sketch how to implement std::function
yourself。