为什么 C++11 不隐式将 lambda 转换为 std::function 对象?
Why doesn't C++11 implicitly convert lambdas to std::function objects?
我实现了一个通用事件发射机类,该类允许代码注册回调,并用参数发射事件。我使用boost。任何类型擦除来存储回调,以便它们可以具有任意参数签名。
一切都起作用,但是由于某种原因,被传递的lambdas必须首先变成std::function
对象。编译器为什么不推断lambda是函数类型?是因为我使用variadic模板的方式吗?
我使用clang(版本字符串: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。
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
D构造器,该构造器可以采用任何类型的任何类型,该类型具有兼容签名的复制/MOVE/operator()
,生成一个具体的自定义类,以实现抽象的内部接口,并将其存储在上述内部值智能指针中。<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<。/p>
然后,它将操作从自己作为价值类型转发到抽象的内部指针,包括完美的转发到调用方法。
发生时,您 can 将lambda存储在std::function
中,就像您可以存储功能指针一样。
但是,有无数不同的std::function
可以存储给定的lambda- 任何东西,这些类型可转换为参数和参数可行,实际上效果很好,std::function
关注。
template
s中C 中的类型扣除在"您可以转换为"的级别上不起作用 - 模式匹配,纯净和简单。由于lambda是与任何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?
}
当boost::any
存储一个值时,它使用该对象的静态类型来确定正在存储哪种类型的对象。然后,如果您指定要存储的内容的静态类型,则只能将any
归还到正确类型的对象。
每个C lambda都与用户不透明的实现定义类型相关联。尽管可以将Lambdas称为功能,但它们并未直接评估std::function
s。将lambda存储在 any
中时,必须使用铸件,以确保存储的静态类型是 std::function
。
希望这会有所帮助!
- Confusion: decltype vs std::function
- 为什么 std::function 可以作为 std::not2 的参数?
- 'max'匹配'std::function<const int &(const int &, const int &)>'无过载
- 传递给std::function template的template参数究竟代表什么
- 绑定派生类方法C++从实例范围之外的分隔 std::function 变量调用
- 将函数包装器转换为 std::function
- 类型擦除的std::function与虚拟函数调用的开销
- C++ std::function 对于类 exept 的所有实例都是空的(只有 Visual2019 编译器问题)
- 如果模板没有可变参数,则 Lambda 被推导出为 std::function
- 将 lambda 表达式传递给 std::function in C++
- 模板类的部分模板专用化,如 std::function
- 可变参数模板参数扩展 类型为 std::function 的类成员
- 从 std::function in C++ 访问模板化 lambda
- 什么是 std::function::argument_type 的替代品?
- C++派生类重载函数(带有 std::function 参数)不可见
- 如何在 qi 符号表中使用 std::function
- 将 std::function 与模板一起使用
- C++ 事件管理器的回调,使用 std::function 和 std:bind 以及派生类作为参数
- 我需要在 std::function 上使用 unique_ptr 吗?
- 如何将函数指针从 std::function 传递到 Linux 克隆?