微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

通过 lambda 函数转发附加参数

如何解决通过 lambda 函数转发附加参数

这是最小的可重现代码

#include <iostream>
#include <string>

void bar(std::string s,int x){        
    std::cout <<std::endl<< __FUNCTION__<<":"<<s<<" "<<x;
}

using f_ptr = void(*)(std::string);


void foo(f_ptr ptr){        
    ptr("Hello world");
}


template<typename T> void fun(T f){
        static int x;
        std::cout <<std::endl<<x++<<std::endl;
        f("Hello World");
}

int main()
{    
    //case:1
    f_ptr ptr1 = [](std::string s){bar(s,10);}; 
   // foo(ptr1);
    
    //case:2
    static int x =10;
    f_ptr ptr2 = [x](std::string s){bar(s,x);}; 
    //foo(ptr2); 
    
    
    //case:3
    int y =10;
    f_ptr ptr3 = [y](std::string s){bar(s,y);}; /* error*/
    foo(ptr3); 
    
    //case:4
    int z = 12;
    fun([z](std::string s){bar(s,z);});
    
    return 0;
}

错误

main.cpp:25:50: error: cannot convert ‘main()::’ to ‘f_ptr {aka void (*)(std::basic_string)}’ in initialization
         f_ptr ptr3 = [y](std::string s){bar(s,y);}; /* error*/

我的问题是,

  1. 有没有办法通过 lambda 转发额外的参数,比如 case:3
  2. 是什么转换导致了 case:3 中的错误
  3. case:4中,typename T推导出什么?

解决方法

  1. 有没有办法通过 lambda 转发额外的参数,比如 case:3
  2. 是什么转换导致了 case:3 中的错误?

带有捕获列表的 Lambda 无法隐式转换为函数指针;没有捕获的 lambdas 可以。您可以改用 std::function

void foo(std::function<void(std::string)> f){        
    f("Hello world");
}

或者像 fun 那样直接使用 lambda。

  1. case:4中,typename T推导出什么?

类型将是唯一的闭包类型; lambda 表达式是该类型的纯右值表达式。

,

一些细节,为什么这会编译而案例 3 不会:

//case:2
static int x =10;
f_ptr ptr2 = [x](std::string s){bar(s,x);}; 

它可以编译,因为它实际上不捕获任何内容,因此可以将 lambda 绑定到函数指针,这在有效捕获情况下是不允许的。标准说:

5.1.1/2 lambda 捕获中的名称应在 lambda 表达式上下文的范围内,并且应是 this 或引用本地 具有自动存储期限的变量或引用。

所以至少没有指定静态变量捕获情况的行为,但不一定是未定义的行为(实现的自由度)。

请注意,捕获静态变量可能会导致令人怀疑的可怕问题,因为从捕获列表的语义中可能期望复制值,但实际上没有复制任何值!

还要注意,这个问题对于全局变量也是一样的(没有自动存储持续时间)!

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。