• C++函数指针接lambda原理


    前言

    我们不详细讲述lambda的基本知识

    我们都使用过lambda,一般来说 ,我们都是auto x = [](){};这样的语句去创建一个lambda,这样的lambda,auto推导的是匿名lambda类的类型,也就是实例化了一个lambda类的对象

    如果不进行捕获,则lambda匿名类实则为空类,如果进行sizeof x的结果会为1,这些都没什么好说的

    当我们使用x()的时候也就是调用这个函数对象operator()

    这些都不是我们今天要讲述的重点,我们想要用函数指针来接lambda表达式,那又会如何呢?

    普通lambda的转换函数

    切记,不管是普通lambda还是泛型lambda(c++14)都不能带捕获才可以有默认的转换函数

    我们举一个例子:

    int(*p)(int) = [](int n) {return n; };
    
    • 1

    像上面这样的一行代码将生成什么呢?如下:

    int main()
    {
          
      class __lambda_2_17
      {
        public: 
        inline /*constexpr */ int operator()(int n) const
        {
          return n;
        }
        
        using retType_2_17 = int (*)(int);
        inline constexpr operator retType_2_17 () const noexcept
        {
          return __invoke;
        }
        
        private: 
        static inline /*constexpr */ int __invoke(int n)
        {
          return __lambda_2_17{}.operator()(n);
        }
        
        
        public:
        // /*constexpr */ __lambda_2_17() = default;
        
      };
      
      using FuncPtr_2 = int (*)(int);
      FuncPtr_2 p = static_cast<int (*)(int)>(__lambda_2_17{}.operator __lambda_2_17::retType_2_17());
      return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    首先它为lambda生成了一个类,这很正常,我们看类内:它有一个public的operator(),一个usingretType_2_17 = int (*)(int);它就是我们转换函数转换的类型

    一个private的静态函数int __invoke(int n),这个静态函数就是为了被转换函数返回函数指针而存在的,它实则是创建临时的lambda对象,再调用它的operator()

    转换函数operator retType_2_17,转换函数相信也都不用介绍了,可隐式转换为函数指针

    最终p实际是是等于了lambda构造临时对象再隐式的调用了转换函数转换为了一个函数指针

    可能有点小绕?实际是想想就理解了,代码只是参考性的

    泛型lambda转换函数

    其实是差不多的,并没有多少的区别,但还是举例子代码给大家看看吧

    int(*p)(int) = [](auto n) {return n; };
    
    • 1

    生成:

    int main()
    {
          
      class __lambda_2_17
      {
        public: 
        template<class type_parameter_0_0>
        inline /*constexpr */ auto operator()(type_parameter_0_0 n) const
        {
          return n;
        }
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        inline /*constexpr */ int operator()<int>(int n) const
        {
          return n;
        }
        #endif
        
        
        /* First instantiated from: insights.cpp:2 */
        #ifdef INSIGHTS_USE_TEMPLATE
        using retType_2_17 = int (*)(int);
        template<>
        inline constexpr operator retType_2_17 () const noexcept
        {
          return __invoke;
        }
        #endif
        
        private: 
        template<class type_parameter_0_0>
        static inline /*constexpr */ auto __invoke(type_parameter_0_0 n)
        {
          return __lambda_2_17{}.operator()<type_parameter_0_0>(n);
        }
        
        #ifdef INSIGHTS_USE_TEMPLATE
        template<>
        static inline /*constexpr */ int __invoke<int>(int n)
        {
          return __lambda_2_17{}.operator()<int>(n);
        }
        #endif
        
        
        public:
        // /*constexpr */ __lambda_2_17() = default;
        
      };
      
      using FuncPtr_2 = int (*)(int);
      FuncPtr_2 p = static_cast<int (*)(int)>(__lambda_2_17{}.operator __lambda_2_17::retType_2_17());
      return 0;
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57

    不再详细说这个例子了,那就用文档的概念和例子结束泛型lambda转换函数的介绍吧

    泛型无捕获 lambda 拥有一个用户定义的转换函数模板,它具有与函数调用运算符模板相同的虚设模板形参列表。如果它的返回类型为空或 auto,那么将由函数模板特化上的返回类型推导获得,而它会以转换函数模板的模板实参推导获得。

    void f1(int (*)(int)) {}
    void f2(char (*)(int)) {}
    void h(int (*)(int)) {}  // #1
    void h(char (*)(int)) {} // #2
     
    auto glambda = [](auto a) { return a; };
    f1(glambda); // OK
    f2(glambda); // 错误:不可转换
    h(glambda);  // OK:调用 #1,因为 #2 不可转换
     
    int& (*fpi)(int*) = [](auto* a) -> auto& { return *a; }; // OK
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    cppreference的说明

    生成代码的网站

  • 相关阅读:
    关于python序列对象
    RPC之 Sekiro 案例
    场景应用:自己设计一个本地缓存(代码实现)
    ExpressGridPack 23 Crack
    c语言用json解析库(jansson)检测字符串是否是json格式的数据
    智慧工地:让工地可视化、数字化、智能化
    DS-fundation-sort1
    LOGO特训营 第三节 首字母创意手法
    蜂鸣器电路设计中选用注意事项--【电路设计】
    静态&动态&文件通讯录
  • 原文地址:https://blog.csdn.net/a4364634611/article/details/127421222