Попробуйте создать модификатор доступа к событиям в стиле C# в C++, используя std::function и std::bind
Я пытаюсь создать обработку событий в стиле C#, т.е. оператор expose += для всех и выставить Invoke
Метод только для содержащего класса.
Я использую std:: function и std:: bind, как описано здесь, для создания механизма обратного вызова: обратный вызов C++ с использованием члена класса
Чтобы включить вызов события только из содержащего класса, я создал Event::Invoke()
метод приватный, а потом я создаю класс друга Event
называется ClassWithEvent
вот есть защищенный метод InvokeEvent
какой призыв Event::Invoke
, Все наследуемые классы ClassWithEvent
может вызвать событие, используя базовый класс InvokeEvent
метод.
Кроме того, я хочу, чтобы у событий были разные типы аргументов, поэтому я создаю базовый класс EventArgs
который может быть расширен другим королем арг.
#include <iostream>
#include <vector>
#include <functional>
using namespace std;
using namespace placeholders;
class EventArgs
{
};
class Event
{
friend class ClassWithEvent;
public:
void operator+=(function<void(const EventArgs &)> callback)
{
m_funcsList.push_back(callback);
}
protected:
void Invoke(const EventArgs & args) const
{
for (function<void(const EventArgs &)> func : m_funcsList)
{
func(args);
}
}
vector<function<void(const EventArgs &)>> m_funcsList;
};
class ClassWithEvent
{
protected:
void InvokeEvent(const Event & event, const EventArgs & args)
{
event.Invoke(args);
}
};
Например, у меня есть ApplesTree
класс с AppleFallEvent
событие у меня есть ApplesCollector
класс, который должен быть уведомлен о падении яблок:
class AppleFallEventArgs : public EventArgs
{
public:
int size;
int weight;
};
class ApplesTree : public ClassWithEvent
{
public:
Event AppleFallEvent;
void triggerAppleFall(int size, int weight)
{
AppleFallEventArgs args;
args.size = size;
args.weight = weight;
ClassWithEvent::InvokeEvent(AppleFallEvent, args);
}
};
class ApplesCollector
{
public:
void HandleAppleFallEvent(const AppleFallEventArgs & args)
{
cout << "Apple size is " << args.size << "weight is " << args.weight << endl;
}
};
int main(int argc, char* argv[])
{
ApplesTree applesTree;
ApplesCollector applesCollector;
applesTree.AppleFallEvent += bind(&ApplesCollector::HandleAppleFallEvent, &applesCollector, _1);
applesTree.triggerAppleFall(1, 2);
return 0;
}
Ну, я пытаюсь скомпилировать это и получаю следующие ошибки:
C2672 'std:: invoke': не найдена соответствующая перегруженная функция
а также
C2893 Не удалось специализировать шаблон функции 'неизвестный тип std::invoke(_Callable &&,_Types &&...)'
Я не могу понять, где проблема, потому что эти ошибки относятся к стандартному стандартному коду, и с ним действительно трудно справиться. В любом случае, я обнаружил, что если я удаляю использование Event::operator+=()
компиляция прошла успешно.
Может кто-то указать, в чем здесь проблема?
Спасибо!
2 ответа
Тебе нужно иметь Event
знать, какие конкретные аргументы он будет использовать. Обратите внимание, что using namespace std;
плохая идея Я также заменил bind
с лямбдой.
// no empty class EventArgs
template<typename EventArgs>
class Event
{
friend class ClassWithEvent;
public:
void operator+=(std::function<void(const EventArgs &)> callback)
{
m_funcsList.emplace_back(std::move(callback));
}
private:
void Invoke(const EventArgs & args) const
{
for (auto & func : m_funcsList)
{
func(args);
}
}
std::vector<std::function<void(const EventArgs &)>> m_funcsList;
};
class ClassWithEvent
{
protected:
template<typename EventArgs>
void InvokeEvent(const Event<EventArgs> & event, const EventArgs & args)
{
event.Invoke(args);
}
};
class AppleFallEventArgs
{
public:
int size;
int weight;
};
class ApplesTree : public ClassWithEvent
{
public:
Event<AppleFallEventArgs> AppleFallEvent;
void triggerAppleFall(int size, int weight)
{
AppleFallEventArgs args;
args.size = size;
args.weight = weight;
InvokeEvent(AppleFallEvent, args);
}
};
class ApplesCollector
{
public:
void HandleAppleFallEvent(const AppleFallEventArgs & args)
{
std::cout << "Apple size is " << args.size << "weight is " << args.weight << std::endl;
}
};
int main(int argc, char* argv[])
{
ApplesTree applesTree;
ApplesCollector applesCollector;
applesTree.AppleFallEvent += [&](auto & args){ applesCollector.HandleAppleFallEvent(args); };
applesTree.triggerAppleFall(1, 2);
return 0;
}
Проблема в том, что метод обработчика событий, который вы пытаетесь связать, не соответствует функции обработчика событий, потому что HandleAppleFallEvent
принимает const AppleFallEventArgs &
вместо const EventArgs &
,
Также есть много ненужного копирования, например for (function<void(const EventArgs &)> func : m_funcsList)
можно заменить на for (function<void(const EventArgs &)> & func : m_funcsList)
,