我实现了一个通用事件发射器类,它允许代码注册回调,并使用参数发出事件.我使用Boost.Any类型擦除来存储回调,以便它们可以具有任意参数签名.
这一切都有效,但由于某种原因,传入的lambdas必须首先变成std::function
对象.为什么编译器不推断lambda是函数类型?是因为我使用可变参数模板的方式吗?
我使用Clang(版本字符串:) Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
.
码:
#include#include #include
Yakk - Adam .. 14
lambda不是a std::function
,std::function
也不是lambda.
lambda是一个语法糖来创建一个如下所示的匿名类:
struct my_lambda { private: int captured_int; double captured_double; char& referenced_char; public: int operator()( float passed_float ) const { // code } }; int captured_int = 7; double captured_double = 3.14; char referenced_char = 'a'; my_lambda closure {captured_int, captured_double, referenced_char}; closure( 2.7f );
由此:
int captured_int = 7; double captured_double = 3.14; char referenced_char = 'a'; auto closure = [=,&referenced_char](float passed_float)->int { // code }; closure(2.7);
my_lambda
实际上是一些不可命名的类型的类型名称.
A std::function
是完全不同的东西.它是一个operator()
使用特定签名实现的对象,并将智能值语义指针存储到覆盖复制/移动/调用操作的抽象接口.它有一个template
构造函数,可以采用任何支持copy/move/operator()
with兼容签名的类型,生成一个实现抽象内部接口的具体自定义类,并将其存储在上面提到的内部值语义智能指针中.
然后它将操作从自身转发为值类型到抽象内部指针,包括完美转发到调用方法.
实际上,您可以将lambda存储在a中std::function
,就像存储函数指针一样.
但是有一大堆不同的东西std::function
可以存储一个给定的lambda - 任何类型可以转换为参数和从参数工作的东西,并且实际上同样有效,就所std::function
涉及的而言.
在C++中template
的类型推导在s中不起作用"你可以转换成" - 它是模式匹配,纯粹和简单.由于lambda是一种与any无关的类型std::function
,因此std::function
不能从中推导出任何类型.
如果C++试图在一般情况下这样做,则必须反转图灵完备过程以确定可以将哪些(如果有的话)类型集传递给它template
以生成与转换兼容的实例.
从理论上讲,我们可以将"运算符推导模板参数"添加到语言中,其中给定的实现者template
可以编写采用某种任意类型的代码,并且他们试图梳理"从这种类型,template
应该使用什么参数实例".但是C++没有这个.
编译器不会推断任何内容,因为编译器实现了C++语言,并且语言的模板参数推导规则不允许以您希望的方式进行推导.
这是一个代表您情况的简单示例:
template <typename T> struct Foo { Foo(int) {} }; template <typename T> void magic(Foo<T> const &); int main() { magic(10); // what is T? }
lambda不是a std::function
,std::function
也不是lambda.
lambda是一个语法糖来创建一个如下所示的匿名类:
struct my_lambda { private: int captured_int; double captured_double; char& referenced_char; public: int operator()( float passed_float ) const { // code } }; int captured_int = 7; double captured_double = 3.14; char referenced_char = 'a'; my_lambda closure {captured_int, captured_double, referenced_char}; closure( 2.7f );
由此:
int captured_int = 7; double captured_double = 3.14; char referenced_char = 'a'; auto closure = [=,&referenced_char](float passed_float)->int { // code }; closure(2.7);
my_lambda
实际上是一些不可命名的类型的类型名称.
A std::function
是完全不同的东西.它是一个operator()
使用特定签名实现的对象,并将智能值语义指针存储到覆盖复制/移动/调用操作的抽象接口.它有一个template
构造函数,可以采用任何支持copy/move/operator()
with兼容签名的类型,生成一个实现抽象内部接口的具体自定义类,并将其存储在上面提到的内部值语义智能指针中.
然后它将操作从自身转发为值类型到抽象内部指针,包括完美转发到调用方法.
实际上,您可以将lambda存储在a中std::function
,就像存储函数指针一样.
但是有一大堆不同的东西std::function
可以存储一个给定的lambda - 任何类型可以转换为参数和从参数工作的东西,并且实际上同样有效,就所std::function
涉及的而言.
在C++中template
的类型推导在s中不起作用"你可以转换成" - 它是模式匹配,纯粹和简单.由于lambda是一种与any无关的类型std::function
,因此std::function
不能从中推导出任何类型.
如果C++试图在一般情况下这样做,则必须反转图灵完备过程以确定可以将哪些(如果有的话)类型集传递给它template
以生成与转换兼容的实例.
从理论上讲,我们可以将"运算符推导模板参数"添加到语言中,其中给定的实现者template
可以编写采用某种任意类型的代码,并且他们试图梳理"从这种类型,template
应该使用什么参数实例".但是C++没有这个.