首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

将lambda包装为std::function会产生错误的结果(这是模板参数推导的危险)

将lambda包装为std::function会产生错误的结果,这是因为模板参数推导的危险。lambda表达式是一种匿名函数,可以在需要函数对象的地方使用。而std::function是一个通用的函数封装器,可以存储、复制、调用任何可调用对象(函数、函数指针、成员函数指针、函数对象等)。

当我们将lambda表达式包装为std::function时,编译器需要进行模板参数推导,以确定std::function的模板参数类型。然而,lambda表达式的类型是一个匿名类型,无法直接推导出来。因此,编译器会尝试将lambda表达式转换为函数指针类型,然后再进行推导。但是,这种转换只适用于没有捕获变量的lambda表达式,对于有捕获变量的lambda表达式,转换为函数指针类型会导致错误的结果。

为了避免这种错误,我们可以使用auto关键字来推导lambda表达式的类型,然后将其直接赋值给std::function,而不是进行模板参数推导。示例代码如下:

代码语言:txt
复制
auto lambda = [](int x) { return x * 2; };
std::function<int(int)> func(lambda);

在这个例子中,lambda表达式的类型被推导为一个匿名类型,并使用auto关键字进行声明。然后,我们将lambda表达式直接赋值给std::function,并指定函数的参数类型和返回类型。

需要注意的是,使用auto关键字推导lambda表达式的类型时,需要确保lambda表达式在声明时已经完整定义了参数类型和返回类型。否则,编译器无法推导出正确的类型,仍然会产生错误的结果。

总结起来,将lambda包装为std::function时,应该使用auto关键字来推导lambda表达式的类型,以避免模板参数推导的错误结果。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

C++11常用新特性快速一览

而这依然会产生问题,将导致了 C++ 中重载特性会发生混乱,考虑: void foo(char *); void foo(int); 对于这两个函数来说,如果 NULL 又被定义为了 0 那么 foo(...那么在运行时,这个 lambda 表达式就会返回一个匿名的闭包实例,是一个右值。所以,我们上面的 lambda 表达式的结果就是一个个闭包。...,但是返回的 lambda 表达式却引用了该变量,当调用这个表达式时,引用的是一个垃圾值,会产生没有意义的结果。...,这很危险,因为你仍然有可能在类对象析构后使用这个 lambda 表达式,那么类似“悬挂引用”的问题也会产生。...当然,如果你在使用了 mova(a) 之后,还继续使用 a,那无疑是搬起石头砸自己的脚,还是会导致严重的运行错误。

2.6K50

Modern c++快速浅析

因为这是一个拷贝指针的操作,因此保留原指针的不可更改指向性并没有太大的意义 auto 大多数情况下auto推断出来的结果和模板类型推导的结果是一样的,不同点在于对大括号初始物的处理 值与指针等推导 const...对于非模板类型参数而言,使用auto进行自动推断会方便很多 template auto是可选项而不是必选项 •对于部分情景而言,使用auto能够避免不少低级错误,如Effective...int arr[pFunc(100)]; 捕获生命周期 C++中其实并没有闭包的概念,更准确的应该将lambda划分为带捕获的lambda以及不带捕获的lambda 在C#这种具备GC机制的语言中,闭包能够延长捕获的变量的生命周期...(理解为能够延长生命周期的按引用捕获) 而C++中的按引用捕获并不能延长对象的生命周期,且按引用捕获会导致lambda表达式包含了对局部对象的引用,这很可能会导致空悬引用 std::function的函数,那么会在编译阶段就得到错误,将错误诊断提前了 = delete 可以用来修饰任何函数,包括非成员函数和模板具现 template void

20410
  • 浅谈 C++ 元编程

    1.4.1 狭义的模板 目前最新的 C++ 将模板分成了 4 类:类模板 (class template),函数模板 (function template),别名模板 (alias template) ...函数 _Factor 有两个重载:一个是对任意非负整数的,一个是对 0 为参数的。前者利用递归产生结果,后者直接返回结果。...定义 TupleToNullable,拆解元组中的所有类型,转化为参数包,再把参数包中所有类型分别传入 TypeToNullable,最后得到的结果重新组装为新的元组。...而对于模板实参内容的检查,则是在实例化的过程中完成的。所以,程序的设计者在编译前,很难发现实例化时可能产生的错误。...在元编程中,很多时候只关心推导的结果,而不是过程。例如,代码中只关心最后的 Factor == 24,而不需要中间过程中产生的临时模板。但是在 N 很大的时候,编译会产生很多临时模板。

    3.1K61

    Effective Modern C++翻译(6)-条款5:auto比显示的类型声明要更好

    使用auto会让你在声明变量时省略掉类型,同时也会防止了手动类型声明带来的正确性和性能上的困扰;虽然按照语言预先定义的规则,一些auto类型推导的结果,在程序员的视角来看却是难以接受的,在这种情况下,知道...,就像你声明函数指针的时候,你必须标注出函数的类型,当你声明std::function的时候,你也必须通过模板的参数标注出函数的类型,例如你可以声明一个叫func的std::function对象,它可以指向以下函数类型的可调用对象...&, const std::unique_ptr&)> func; 因为lambda表达式产生的可调用对象,闭包也可以通过std::function对象表示,这意味着我们可以声明新的版本的...,并且需要的空间也一样,而用std::function声明的变量持有的闭包是std::function模板的一个实例,对任何的给定的函数原型,所需要的内存大小都是一样的,如果分配的大小不足,std::function...,所以在使用auto还是std::function声明一个闭包的较量中,auto获胜了(一个类似的参数可以通过auto或者std::function来产生,持有std::bind的调用结果,但是根据条款

    903100

    Chapter 6:Lambda Expressions

    每个lambda都会使得编译器产生一个独一无二的closure class。一个lambda内的语句会变成它的closure class的成员函数中可执行的指令。 2....默认情况下,从lambda表达式产生的闭包类的内部成员函数operator(),是const属性的,这使得闭包里面的所有数据成员在lambda体内都是const属性的,而bind对象里面移动过来的data...的闭包类中是一个模板,但是如果normalize函数区分左值参数和右值参数,上面的写法不完全对,要实现完美转发的话需要做两点改动 把x声明为一个通用引用 使用std::forward把x转发给normalize...return normalize(std::forward(x); }; //1,decltype推导x的类型A //2.std::forward根据A推导模板参数类型...,得到左值引用参数;右值作用在通用引用参数,得到右值引用参数 尽管decltype在把右值参数推导为右值引用类型而不是非引用类型(std::forward中T要求的),但是最终转发的结果一样

    1.8K50

    C++11新特性学习笔记

    C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto、 decltype,和模板的大量改进。...(2, 1.0); // OK:args含有两个实参int和double 省略号“…”的作用有两个: \1) 声明一个参数包,这个参数包中可以包含0到任意个模板参数 \2) 在模板定义的右边,可以将参数包展开成一个一个独立的参数...6.2 可变参数模板类 6.2.1 继承方式展开参数包 可变参数模板类的展开一般需要定义2 ~ 3个类,包含类声明和特化的模板类: template class BMW{};...C++11中,新增加了一个std::function类模板,它是对C++中现有的可调用实体的一种类型安全的包裹。...9.2.3.3 lambda类型 lambda表达式的类型在C++11中被称为“闭包类型”,每一个lambda表达式则会产生一个临时对象(右值)。因此,严格地将,lambda函数并非函数指针。

    2.1K20

    C++11新特性学习笔记

    C++11包括大量的新特性:包括lambda表达式,类型推导关键字auto、 decltype,和模板的大量改进。...(2, 1.0); // OK:args含有两个实参int和double 省略号“…”的作用有两个: \1) 声明一个参数包,这个参数包中可以包含0到任意个模板参数 \2) 在模板定义的右边,可以将参数包展开成一个一个独立的参数...6.2 可变参数模板类 6.2.1 继承方式展开参数包 可变参数模板类的展开一般需要定义2 ~ 3个类,包含类声明和特化的模板类: template class BMW{};...C++11中,新增加了一个std::function类模板,它是对C++中现有的可调用实体的一种类型安全的包裹。...9.2.3.3 lambda类型 lambda表达式的类型在C++11中被称为“闭包类型”,每一个lambda表达式则会产生一个临时对象(右值)。因此,严格地将,lambda函数并非函数指针。

    2.2K20

    C++ —— 剑斩旧我 破茧成蝶—C++11

    Function(T&& t)函数模板程序中,假设实参是int右值,模板参数T的推导int,实参是int左值,模板参数T的推导int&,再结合引⽤折叠规则,就实现了实参是左值,实例化出左值引⽤版本形参的...t) Function(a);// 左值 // std::move(a)是右值,推导出T为int,模板实例化为void Function(int&& t) Function(std::move...(int& t) Function(a);// 左值 // std::move(a)是右值,推导出T为int,模板实例化为void Function(int&& t) Function(std:...Function内部会编译报错,x不能++ Function(b);// const 左值 // std::move(b)右值,推导出T为const int,模板实例化为void Function...C++还⽀持更复杂的包扩展,直接将参数包依次展开依次作为实参给⼀个函数去处理 底层的实现细节: 包扩展的方式1: //包扩展的方式 void ShowList() { // 编译器时递归的终

    5500

    Effective Modern C++翻译(3)-条款2:明白auto类型推导

    模板的类型推导涉及了模板,函数和参数,但是auto的类型推导却没有涉及其中的任何一个。...//同上 这是由于auto类型推导的一个特殊的规则,当变量使用大括号的初始化式(braced initializer)初始化的时候,被推导出的类型是std::initializer_list,如果这个类型不能被推导出来...std::initializer_list模板的类型,而模板类型推导面对大括号的初始化式(braced initializer)时,代码将不会通过(这是由于完美转发perfect forwarding的结果...的lambda表达式可能需要在参数的声明时使用auto,不管怎样,这些auto的使用,采用的是模板类型推导的规则,而不是auto类型推导规则,这意味着,大括号的初始化式会造成类型推导的失败,所以一个带有...auto用于C++14的lambda(产生一个通用的lambda(generic lambda))的参数类型说明符时, std::vector v; auto resetV = [&v](const

    714100

    【C++】C++11

    Function(T&& t)函数模板程序中,假设实参是int右值,模板参数T的推导int,实参是int左值,模 板参数T的推导int&,再结合引⽤折叠规则,就实现了实参是左值,实例化出左值引⽤版本形参的...// std::move(a) 是右值,推导出 T 为 int ,模板实例化为 void Function(int&& t) 21 Function (std:: move (a));...// std::move(b) 右值,推导出 T 为 const int ,模板实例化为 void Function(const int&& t) Function (std:...,可变数⽬的参数被称 为参数包,存在两种参数包:模板参数包,表⽰零或多个模板参数;函数参数包:表⽰零或多个函 数参数。...我们通过在模式的右边放⼀个省略号(...)来触发扩展操作。底层 的实现细节如图1所⽰。 C++还⽀持更复杂的包扩展,直接将参数包依次展开依次作为实参给⼀个函数去处理。

    9210

    C++进阶:C++11(列表初始化、右值引用与移动构造移动赋值、可变参数模版...Args、lambda表达式、function包装器)

    模板参数包允许在模板参数列表中接受任意数量的参数,并通过展开(expansion)来处理这些参数。...一个基础的模版: // Args是一个模板参数包,args是一个函数形参参数包 // 声明一个参数包Args...args,这个参数包中可以包含0到任意个模板参数。...我们无法直接获取参数包args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点,即如何展开可变模版参数。...返回值类型 -> return-type:用于指定Lambda函数的返回值类型,可以省略,编译器会根据返回语句进行推导(一般情况都不写)。...通过std::function的模板参数,可以指定存储的可调用对象的类型。 存储可调用对象:std::function可以存储各种可调用对象,如函数指针、函数对象、Lambda表达式等。

    15600

    CC++开发基础——lambda表达式与std::bind闭包

    本章主要内容: 一,lambda表达式 1.基本概念 2.关于捕获子句 3.常见的捕获方式 二,闭包与std::bind模板 1.什么是闭包...所以下面这两个捕获子句会产生编译错误: [&, &counter] [=, &counter, number] 方式四,捕获this指针 如果一个对象的成员函数中有lambda表达式,那么这个lambda...: 3 6 9 12 二,闭包与std::bind模板 1.什么是闭包 闭包( Closure)这个概念起源于函数式编程,是指外部变量与函数之间的绑定,可以这样理解,捕获了外部变量的lambda表达式是一种闭包...std::bind可以预先指定函数的所有参数,也可以将函数的部分参数预先指定好,剩下的参数等真正调用的时候再指定。 3.std::bind的用法 假如有一个计算两个数字相加的函数。...int add(int first, int second) { return first + second; } std::bind将函数名作为其第一个参数,后面的参数用"_1,_2"这样的占位符来预留

    1K30

    C++一分钟之-泛型Lambda表达式

    在C++14中,引入了泛型lambda表达式,这是一项强大的特性,允许我们编写更加灵活和通用的代码。...本文将深入浅出地介绍泛型lambda表达式的概念、常见问题、易错点及如何避免,并通过代码示例加深理解。 什么是泛型Lambda表达式? 在C++14之前,lambda表达式只能捕获特定类型的参数。...隐式转换 泛型lambda可能会接受隐式转换,这可能导致意外的行为。例如,传递一个整数给期望浮点数的lambda。...模板参数推导 当在模板上下文中使用泛型lambda时,需要小心模板参数的推导规则,否则可能引起编译错误或非预期的行为。...模板参数显式指定 在模板函数中使用泛型lambda时,考虑显式指定模板参数,避免依赖于复杂的模板参数推导。

    11310

    C++一分钟之-泛型Lambda表达式

    在C++14中,引入了泛型lambda表达式,这是一项强大的特性,允许我们编写更加灵活和通用的代码。...本文将深入浅出地介绍泛型lambda表达式的概念、常见问题、易错点及如何避免,并通过代码示例加深理解。什么是泛型Lambda表达式?在C++14之前,lambda表达式只能捕获特定类型的参数。...例如,如果a和b需要进行比较,但某些类型没有定义错误。隐式转换undefined泛型lambda可能会接受隐式转换,这可能导致意外的行为。...例如,传递一个整数给期望浮点数的lambda。模板参数推导undefined当在模板上下文中使用泛型lambda时,需要小心模板参数的推导规则,否则可能引起编译错误或非预期的行为。...模板参数显式指定undefined在模板函数中使用泛型lambda时,考虑显式指定模板参数,避免依赖于复杂的模板参数推导。

    17010

    【C++11】解锁C++11新纪元:深入探索Lambda表达式的奥秘

    std::function的引入,使得C++的函数式编程风格得以更加流畅地实现,同时也为C++的面向对象编程和泛型编程提供了强大的支持 本篇旨在深入探讨C++11中的lambda表达式和std::function...然而由于可变模版参数比较抽象,使用起来需要一定的技巧,所以这块还是比较晦涩的 可变参数的函数模板: // Args是一个模板参数包,args是一个函数形参参数包 // 声明一个参数包Args...args...,这个参数包中可以包含0到任意个模板参数。...args中的每个参数的,只能通过展开参数包的方式来获取参数包中的每个参数,这是使用可变模版参数的一个主要特点,也是最大的难点 递归函数方式展开参数包: void _ShowList() { cout...此外,我们还探讨了lambda表达式的类型——std::function和模板参数自动推导(如auto)如何进一步促进了lambda表达式的使用,使得它们可以轻松地与标准库中的算法和其他函数模板协同工作

    8410

    Effective Modern C++翻译(5)-条款4:了解如何观察推导出的类型

    他们可能想知道如果我用一个万能引用(见条款26)替代一个左值的常量形参(例如在函数的参数列表中用T&&替代const T&)模板类型推导的结果会改变吗?...编译器的诊断 知道编译器对某一类型推导出的结果一个有效方法是让它产生一个编译期的错误,因为错误的报告肯定会提到导致错误的类型。...== "Type Displayer" 尝试实例化这个模板会产生一个错误信息,因为没有模板的定义,想要查看x和y的类型只需要用它们的类型实例化TD TD xType; // 引起错误的信息包括了...和std::type_info::name来产生用户自定义格式的字符串表达) 如果你经常需要使用这个方法,并且认为花费在调试,文档,维护上的努力是值得的,那么这是一个合理的方法(If you’d use...typeid更好的代码的, 你需要注意到很多编译器都提供了语言的扩展来产生一个函数签名的字符串表达,包括从模板中实例化的函数,模板和模板参数的类型。

    72480

    【Cocos2d-x游戏开发】细数Cocos2d-x开发中那些常用的C++11知识

    void foo(char *); 5.Lambda特性 lambda表达式是一个非常好的新特性,当你需要在程序中添加一个新的临时函数时,直接使用Lambda函数,会让你感觉到原来写程序还可以这么爽~...,这种参数集合一般被称为闭包,[ ]中可以填写下面的几种类型的参数,将定义lambda函数作用域内的变量传入函数体中。   ...[=,&a]除了a用引用的方式传入,其他变量都以传值的方式传入   下面让我们通过一个例子来了解一下,当在lambda中使用了“=”传入的参数,且对引用参数或者外部参数进行赋值操作之后,会产生意想不到的结果...使用std::function可以存储Lambda函数,比如可以用function来存储func0,用function来存储func1,带有参数的函数可以直接在()内输入参数类型...,静态函数和类的公有成员函数,前两者和lambda的用法一样,直接将函数名赋值给function对象即可(无法识别重载的函数),但类的成员函数需要使用bind来绑定: ClassA *obj =

    48330

    C++17常用新特性

    2 C++17新特性 2.1 折叠表达式 从C++17开始,可以使用二元操作符对形参包中的参数进行计算,这一特性主要针对可变参数模板进行提升,可以分为左折叠和右折叠。支持的二元操作符多达32个。...return 0; } 运行结果: sum1=6 sum2=16 2.2 类模板实参推导 对模板进行实例化时,不需要指定模板参数,编译器会根据传入的实参进行类型推导。...根据变量及变量模板的初始化或者声明进行推导 std::pair p(2, 4.5); // 推导出 std::pair p(2, 4.5); std::tuple t(...作为非类型模板参数 在模板参数中使用auto作为关键字时,模板实例化传入非类型值,auto可以推导出参数类型。...::coutstd::endl; return 0; } 代码运行结果为:3; 需要注意的是C++17目前还不支持参数类型是浮点型的推导。

    2.3K20
    领券