【问题标题】:C++11 lambdas to Function PointerC++11 lambdas 到函数指针
【发布时间】:2012-06-15 08:51:57
【问题描述】:

我开始使用 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 运行时),它有一个简单的函数实现来解决这个问题? p>

【问题讨论】:

  • 听起来像是XY problem 的一个实例。
  • 您不能将捕获的 lambda 转换为函数指针。解释你想要做什么。
  • 您已经(糟糕地)解释了一个尝试的解决方案,但没有描述您的实际问题是什么。请告诉我们您的实际问题是什么
  • @Antonio:在查看了std::function 的实现后,我对我的答案进行了一些更正。你应该看看。
  • 这能回答你的问题吗? Passing capturing lambda as function pointer

标签: c++ c++11


【解决方案1】:

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

那么您可能需要编写自己的等价于std::function

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

确实,std::function 中唯一需要 RTTI 的是target_typetarget 函数,它们并不是世界上最有用的函数。假设您使用的实现不需要 RTTI 来完成日常业务,您也许可以只使用 std::function 而无需调用这些函数。

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

【讨论】:

    【解决方案2】:

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

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


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

    【讨论】:

    • 好吧,如果你像 const int c; [c](int i)-&gt;int{return i*c;} 这样按值传递它会很有意义......
    • @BarnabasSzabolcs:这取决于,考虑std::function&lt;int(int)&gt; f(int x) { const int c = x; return [c](int i){return i*c;} };f 返回的函子取决于它的参数,因此具有状态。只有当捕获是一个常量表达式时,它才能被分解为一个普通函数。
    • 嗯。我同意,部分。它仍然可以取消,但解决方案可能很昂贵,因为程序每次都需要复制 lambda 函数的代码并更改函数代码中 c 的值。 (或者如果不复制函数的整个代码,它需要进行有计划的跳转,跳转会减慢速度。)
    • @BarnabasSzabolcs:我认为这甚至不能做到,考虑到函数的参数可以是运行时值(例如从用户输入中读取)并且您不能基于运行时创建函数价值观。您可以想象将值存储在一边,但要确保不同的 lambda 在创建新 lambda 时不会破坏其值,这反过来又需要动态内存,其使用对于编译器来说是难以处理的......
    • 在 VS2013 和 xcode6 上都试过了。没有捕获的Lambda可以转换为函数指针,谢谢指出。
    【解决方案3】:

    如前所述,只有不捕获任何内容的 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 变量。

    【讨论】:

      【解决方案4】:

      您可以使用std::function,它不需要任何“运行时”。否则,look here for a sketch how to implement std::function yourself

      【讨论】:

      • 我不能使用 std::function 因为我的代码需要 RTTI 并且异常被禁用。
      猜你喜欢
      • 1970-01-01
      • 2012-10-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-25
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      相关资源
      最近更新 更多