Я реализовал общий класс эмиттеров событий, который позволяет коду регистрировать обратные вызовы и испускать события с аргументами. Я использовал стирание типа Boost.Any для хранения обратных вызовов, чтобы они могли иметь произвольные сигнатуры параметров.
Все работает, но по какой-то причине lambdas передается, сначала должен быть превращен в объекты std::function
. Почему компилятор не делает вывод, что лямбда является типом функции? Это из-за того, как я использую вариативные шаблоны?
Я использую 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;
}