为什么C ++ 11不会将lambdas隐式转换为std :: function对象? [英] Why doesn't C++11 implicitly convert lambdas to std::function objects?
问题描述
我实现了一个通用的事件发射器类,它允许代码注册回调,并发出带有参数的事件。我使用Boost.Any类型擦除来存储回调,以便他们可以有任意参数签名。
I implemented a generic event emitter class which allows code to register callbacks, and emit events with arguments. I used Boost.Any type erasure to store the callbacks so they can have arbitrary parameter signatures.
这一切都行之有效,但由于某种原因,传递的lambda必须先变成 std :: function
对象。为什么编译器不推断lambda是函数类型?是因为我使用可变参数模板的方式?
It all works, but for some reason, lambdas being passed in must first be turned into std::function
objects. Why doesn't the compiler infer that the lambda is the function type? Is it because of the way I use variadic templates?
我使用Clang(版本字符串: Apple LLVM版本5.0(clang-500.2.79) (基于LLVM 3.3svn)
)。
I use Clang (version string: Apple LLVM version 5.0 (clang-500.2.79) (based on LLVM 3.3svn)
).
代码:
#include <functional>
#include <iostream>
#include <map>
#include <string>
#include <vector>
#include <boost/any.hpp>
using std::cout;
using std::endl;
using std::function;
using std::map;
using std::string;
using std::vector;
class emitter {
public:
template <typename... Args>
void on(string const& event_type, function<void (Args...)> const& f) {
_listeners[event_type].push_back(f);
}
template <typename... Args>
void emit(string const& event_type, Args... args) {
auto listeners = _listeners.find(event_type);
for (auto l : listeners->second) {
auto lf = boost::any_cast<function<void (Args...)>>(l);
lf(args...);
}
}
private:
map<string, vector<boost::any>> _listeners;
};
int main(int argc, char** argv) {
emitter e;
int capture = 6;
// Not sure why Clang (at least) can't deduce the type of the lambda. I don't
// think the explicit function<...> business should be necessary.
e.on("my event",
function<void ()>( // <--- why is this necessary?
[&] () {
cout << "my event occurred " << capture << endl;
}));
e.on("my event 2",
function<void (int)>(
[&] (int x) {
cout << "my event 2 occurred: " << x << endl;
}));
e.on("my event 3",
function<void (double)>(
[&] (double x) {
cout << "my event 3 occurred: " << x << endl;
}));
e.on("my event 4",
function<void (int, double)>(
[&] (int x, double y) {
cout << "my event 4 occurred: " << x << " " << y << endl;
}));
e.emit("my event");
e.emit("my event 2", 1);
e.emit("my event 3", 3.14159);
e.emit("my event 4", 10, 3.14159);
return EXIT_SUCCESS;
}
推荐答案
lambda不是 std :: function
和 std :: function
不是lambda。
A lambda is not a std::function
, and std::function
is not a lambda.
lambda是一种语法糖,用于创建一个如下所示的匿名类:
A lambda is syntactic sugar to create an anonymous class that looks like this:
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);
是一些不可命名的类型。
with the type name of the my_lambda
actually being some unnameable type.
一个 std :: function
是一个完全不同的东西。它是一个具有特定签名的实现 operator()
的对象,并将一个智能值语义指针存储到一个包含复制/移动/调用操作的抽象接口。它有一个模板
d构造函数,可以采用支持复制/移动/ operator()
,生成实现抽象内部接口的具体自定义类,并将其存储在上述内部值 - 语义智能指针中。
A std::function
is a completely different thing. It is an object that does implement operator()
with a particular signature, and stores a smart value-semantics pointer to an abstract interface that covers copy/move/invoke operations. It has a template
d constructor that can take any type that supports copy/move/operator()
with a compatible signature, generates a concrete custom class that implement the abstract internal interface, and stores it in the above mentioned internal value-semantics smart pointer.
然后将操作从自身转发为
It then forwards operations from itself as a value-type to the abstract internal pointer, including perfect forwarding to the invocation method.
在这种情况下,您可以在一个 std :: function
,就像你可以存储一个函数指针。
As it happens, you can store a lambda in a std::function
, just like you can store a function pointer.
但是有很多不同的 std :: function
可以存储一个给定的lambda - 任何东西,其中类型可以转换为和从参数工作,
But there are a whole myriad of different std::function
that could store a given lambda -- anything where the types are convertible to and from the arguments works, and in fact works equally well, as far as the std::function
is concerned.
在<$ c $中键入C ++中的扣除c> template s不能在你可以转换为级别工作 - 它是模式匹配,纯粹和简单。由于lambda是与任何 std :: function
无关的类型,因此不能从 std :: function
Type deduction in C++ in template
s does not work at the level "can you convert into" -- it is pattern matching, pure and simple. As the lambda is a type unrelated to any std::function
, no std::function
type can be deduced from it.
如果C ++试图在一般情况下这样做,它必须反转一个图灵完成过程来确定什么(如果有的话)
If C++ tried to do that in the general case, it would have to invert a Turing-complete process to determine what (if any) set of types could be passed to the template
in order to generate a conversion-compatible instance.
在理论上,我们可以添加运算符,并将其传递给模板
从到语言中推导模板参数,其中给定的模板
的实现者可以编写采用某种任意类型的代码,并且他们试图从这种类型, template
参数应该用于实例。但C ++没有这个。
In theory, we could add "operator deduce template arguments from" to the language, where the implementers of a given template
can write code that takes some arbitrary type, and they attempt to tease out "from this type, what template
parameters should be used for an instance". But C++ does not have this.
这篇关于为什么C ++ 11不会将lambdas隐式转换为std :: function对象?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!