10

我开始使用 C++11 lambda 开发应用程序,并且需要将某些类型转换为函数指针。这在 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

如果使用auto,它可以正常工作:

const char * text = "Test!";

auto test = [&]()
{
    puts(text);
};

test();

我的问题是:如何使用[&]为 lambda 创建类型?就我而言,我不能使用 STL std::function(因为我的程序不使用 C++ RTTI 和 EXCEPTIONS 运行时),它有一个简单的函数实现来解决这个问题?

4

4 回答 4

10

我不能使用 STL std::function(因为我的程序不使用 C++ RTTI 和 EXCEPTIONS 运行时)

然后您可能需要编写自己的等价于std::function.

类型擦除的通常实现std::function不需要 RTTI 来实现其大部分功能;它通过常规的虚函数调用工作。所以编写自己的版本是可行的。

实际上,唯一std::function需要RTTI的是target_typeandtarget函数,它们并不是世界上最有用的函数。std::function假设您正在使用的实现不需要 RTTI 来完成其日常业务,您也许可以在不调用这些函数的情况下直接使用。

throw通常,当您禁用异常处理时,程序会在遇到语句时简单地关闭并出错。而且由于 astd::function会发出的大多数异常不是您能够从中恢复的类型(调用 empty function、内存不足等),您可能可以std::function按原样使用。

于 2012-06-12T14:14:38.573 回答
9

只有没有捕获的 lambda 可以转换为函数指针。这是仅针对这种特殊情况 [*] 的 lambdas 的扩展。通常,lambda 是函数对象,不能将函数对象转换为函数。

具有状态(捕获)的 lambda 的替代方法是使用std::function而不是普通函数指针。


[*]:如果保存状态的 lambda 可以转换为函数指针,那么状态将保存在哪里?(请注意,这个特定的 lambda 可能有多个实例,每个实例都有自己的状态,需要单独维护)

于 2012-06-12T14:00:29.723 回答
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 变量。

于 2012-06-12T18:06:12.927 回答
2

您可以使用std::function,它不需要任何“运行时”。否则,请在此处查找如何实现std::function自己的草图。

于 2012-06-12T13:10:04.607 回答