C++ 如何将Lambda转换成函数指针

 更新时间:2022年11月05日 11:16:44   作者:斗酒神僧  
这篇文章主要介绍了C++ 如何将Lambda转换成函数指针,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

没有捕获任何变量的Lambda表达式可以转换成与它的调用原型一致的函数指针。

参考下面的代码

void example1()
{
    auto add = [](int x, int y)
    {
        return x + y;
    };
    int x = 2, y = 3;
    int z1 = add(x, y);                  // 调用Lambda
    int(*f)(int, int) = add;             // Lambda转换成函数指针
    int z2 = f(x, y);                    // 调用函数
    cout << z1 << ", " << z2 << endl;
}

Lambda是实现了函数调用运算符的匿名类(anonymous class)。对于每一个Lambda,编译器创建匿名类,并定义相应的数据成员存储Lambda捕获的变量。没有捕获变量的Lambda不包含任何含成员变量。

一个没有任何成员变量(包括没有虚函数表指针)的类型,在空指针上调用成员函数也不会有任何的问题,因为它的成员函数不会通过this指针访问内存。

当Lambda向函数指针的转换时,编译器为Lambda的匿名类实现函数指针类型转换运算符。

上面的例子中,编译器实现operator int(*)(int, int)。

下面是Visual C++编译器为语句int(*f)(int, int) = add生成的64位汇编代码:

lea         rcx,[add]  
call        <lambda_0e153cdea67ea404383c23c1022dd325>::operator int (__cdecl*)(int,int) 
mov         qword ptr [f],rax  

第1行,变量"add"的地址存入rcx寄存器;第2行,调用匿名类的函数指针类型转换运算符;第3行,返回结果存入变量f。

提示:在默认的成员函数调用约定__thiscall下,this指针通过rcx寄存器传递, 有关__thiscall的详细内容,请参考:https://docs.microsoft.com/en-us/cpp/cpp/thiscall

下面是类型转换运算符实现的一行关键汇编代码

lea         rax,[<lambda_0e153cdea67ea404383c23c1022dd325>::<lambda_invoker_cdecl>] 

这一行把匿名类的名为lambda_invoker_cdecl的函数地址存入用于返回结果的寄存器rax。因为只有类的静态函数可以转换成非成员函数指针,所以lambda_invoker_cdecl是静态函数。下面是此函数其中一段汇编代码:

xor         rcx,rcx  
call        <lambda_0e153cdea67ea404383c23c1022dd325>::operator() 

第一行,rcx寄存器清0,即this指针置0;第二行,调用operator()。

综合上面的分析,得出Lambda转换成函数指针的一种可能的实现方式,参考下面的代码:

typedef int(*FUNCADD)(int, int);

// 实现两个整数相加的函数对象
class add_function_object
{
public:
    // 函数调用运算符
    int operator()(int x, int y)const
    {
        return x + y;
    }
    // 函数指针类型转换运算符
    operator FUNCADD()const
    {
        return add;
    }
private:
    static int add(int x, int y)
    {
        add_function_object* obj = nullptr;
        return obj->operator()(x, y);
    }
};

void example2()
{
    int x = 2, y = 3;
    add_function_object add;
    int z1 = add(x, y);
    auto fadd = add.operator FUNCADD();
    int z2 = fadd(x, y);
    cout << z1 << ", " << z2 << endl;
}

从C++17起,没有捕获任何变量的Lambda可以用作值类型模板实参,参考下面的代码:

typedef int (*INTEGER_OPERATION)(int, int);

int do_integer_operation(INTEGER_OPERATION op, int x, int y)
{
    return op(x, y);
}

template <INTEGER_OPERATION op>
int integer_operation_t(int x, int y)
{
    return op(x, y);
}

void example3()
{
    auto add = [](int x, int y)
    {
        return x + y;
    };
    auto sub = [](int x, int y)
    {
        return x - y;
    };
    int z1 = integer_operation_t<add>(2, 3);
    int z2 = do_integer_operation(integer_operation_t<sub>, 2, 3);
    cout << "z1 : " << z1 << ", z2 : " << z2 << endl;
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。

相关文章

  • C++实例分析讲解临时对象与右值引用的用法

    C++实例分析讲解临时对象与右值引用的用法

    对性能来说,许多的问题都需要和出现频率及本身执行一次的开销挂钩,有些问题虽然看似比较开销较大,但是很少会执行到,那也不会对程序有大的影响;同样一个很小开销的函数执行很频繁,同样会对程序的执行效率有很大影响。本章中作者主要根据临时对象来阐述这样一个观点
    2022-08-08
  • C语言实现的猴子分桃问题算法解决方案

    C语言实现的猴子分桃问题算法解决方案

    这篇文章主要介绍了C语言实现的猴子分桃问题算法,较为详细的分析了猴子分桃问题算法的原理与通过递归算法解决问题的相关实现技巧,需要的朋友可以参考下
    2016-10-10
  • C语言实现简单的三子棋小游戏

    C语言实现简单的三子棋小游戏

    这篇文章主要为大家详细介绍了C语言实现简单的三子棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-03-03
  • 浅谈C++ 虚函数分析

    浅谈C++ 虚函数分析

    这篇文章主要介绍了浅谈C++ 虚函数分析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-02-02
  • C++实现FTP综合应用详解

    C++实现FTP综合应用详解

    这篇文章主要为大家详细介绍了C++实现FTP综合应用,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-08-08
  • C语言实现扫雷小游戏的示例代码

    C语言实现扫雷小游戏的示例代码

    这篇文中主要为大家详细介绍了如何利用C语言实现经典的扫雷小游戏。扫雷小游戏主要是利用字符数组、循环语句和函数实现,感兴趣的小伙伴可以了解一下
    2022-10-10
  • 基于Qt实现简单的计算器

    基于Qt实现简单的计算器

    这篇文章主要介绍了如何使用Qt框架实现一个简单的计算器应用,我们将使用C++编程语言和Qt的图形用户界面库来开发这个应用,并展示如何实现基本的算术操作,希望对大家有所帮助
    2023-11-11
  • C语言中字符串库函数的实现及模拟

    C语言中字符串库函数的实现及模拟

    C语言中有很多数据类型,比如int(整数类型)、char(字符类型)、以及浮点型的double(双精度)等。但是有一点就是我们发现这里并没有提到我们常见的有关字符串的类型。本文为大家介绍了C语言中字符串库函数的实现及模拟,需要的可以参考一下
    2022-11-11
  • VS2019上配置CUDA的环境步骤

    VS2019上配置CUDA的环境步骤

    本文主要介绍了VS2019上配置CUDA的环境步骤,文中通过图文示例介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • C++ 设置控制台(命令行)窗口 光标位置,及前背景颜色

    C++ 设置控制台(命令行)窗口 光标位置,及前背景颜色

    这篇文章主要介绍了C++ 设置控制台(命令行)窗口 光标位置,及前背景颜色,需要的朋友可以参考下
    2019-04-04

最新评论