template<typename TObject, typename TEventArgs> requires std::derived_from<TEventArgs, EventArgs>
void operator()(TObject* sender, const TEventArgs& e) const
{
for(const THandler& handler : _handlers)
{
handler(sender, e);
}
}
_handlers
это коллекция делегатов, то они у тебя все одного типа и тебе про них все итак известно. template<typename THandler>
class Event
{
protected:
std::forward_list<THandler> _handlers;
public:
void operator+=(auto&& handler)
{
_handlers.emplace_front(std::forward<decltype(handler)>(handler));
}
void operator-=(auto&& handler)
{
_handlers.remove(std::forward<decltype(handler)>(handler));
}
operator bool() const noexcept
{
return !_handlers.empty();
}
template<typename TObject, typename TEventArgs> requires std::derived_from<TEventArgs, EventArgs>
void operator()(TObject* sender, const TEventArgs& e) const
{
for(const THandler& handler : _handlers)
{
handler(sender, e);
}
}
void Clear() noexcept
{
_handlers.clear();
}
};
template<typename TObject, typename TEventArgs> requires std::derived_from<TEventArgs, EventArgs>
class EventHandler: public std::function<void(TObject*, const TEventArgs&)>
{
public:
using ObjectType = TObject;
using ArgsType = TEventArgs;
};
void operator()(THandler::ObjectType* sender, const THandler::ArgsType& e) const
{
for(const THandler& handler : _handlers)
{
handler(sender, e);
}
}
Event
никуда не годится. Он неконтролируемый вообще.void operator+=(auto&& handler)
auto&&
- это универсальное обобщение. Конкретный тип из него будет выведен в момент передачи аргумента._handlers.emplace_front(std::forward<decltype(handler)>(handler));
код будет пытаться привести переданный тобой хендлер к типу THandler
.template<typename TObject, typename TEventArgs> requires std::derived_from<TEventArgs, EventArgs>
void operator()(TObject* sender, const TEventArgs& e) const
THandler
.std::function
. Постарайся разобраться с возможностями, которые тебе открывает мой совет.template<typename TObject, typename TEventArgs>
requires std::derived_from<TEventArgs, EventArgs>
class EventHandler: public std::function<void(TObject*, const TEventArgs&)>
{
public:
using Base = std::function<void(TObject*, const TEventArgs&)>;
using Object = TObject;
using EventArgs = TEventArgs;
public:
EventHandler() = default;
template<typename TCallable>
requires !std::is_same_v<std::decay_t<TCallable>, EventHandler>
EventHandler(TCallable&& handler):
Base(std::forward<TCallable>(handler))
{}
EventHandler(const EventHandler& handler):
Base(static_cast<const Base&>(handler))
{}
EventHandler(EventHandler&& handler) noexcept:
Base(static_cast<Base&&>(handler))
{}
template<typename TCallable>
requires !std::is_same_v<std::decay_t<TCallable>, EventHandler>
EventHandler& operator=(TCallable&& handler)
{
Base::operator=(std::forward<TCallable>(handler));
return *this;
}
EventHandler& operator=(const EventHandler& handler)
{
Base::operator=(static_cast<const Base&>(handler));
return *this;
}
EventHandler& operator=(EventHandler&& handler) noexcept
{
Base::operator=(static_cast<Base&&>(handler));
return *this;
}
bool operator==(const EventHandler& eventHandler) const noexcept
{
return this->target_type() == eventHandler.target_type();
}
bool operator!=(const EventHandler& eventHandler) const noexcept
{
return !operator==(eventHandler);
}
};
template<typename TEventHandler,
typename TObject = typename TEventHandler::Object,
typename TEventArgs = typename TEventHandler::EventArgs> requires
std::is_base_of_v<EventHandler<typename TEventHandler::Object,
typename TEventHandler::EventArgs>, TEventHandler>
class Event
{
public:
using EventHanlder = TEventHandler;
protected:
std::forward_list<TEventHandler> _handlers;
public:
void Clear() noexcept { _handlers.clear(); }
template<typename TCallable>
requires !std::is_same_v<std::decay_t<TCallable>, TEventHandler>
void operator+=(TCallable&& callable)
{
_handlers.emplace_front(std::forward<TCallable>(callable));
}
void operator+=(TEventHandler&& handler)
{
_handlers.push_front(std::move(handler));
}
void operator+=(const TEventHandler& handler)
{
_handlers.push_front(handler);
}
template<typename TCallable>
requires !std::is_same_v<std::decay_t<TCallable>, TEventHandler>
void operator-=(TCallable&& callable)
{
_handlers.remove(std::forward<TCallable>(callable));
}
void operator-=(TEventHandler&& handler)
{
_handlers.remove(std::move(handler));
}
void operator-=(const TEventHandler& handler)
{
_handlers.remove(handler);
}
operator bool() const noexcept { return !_handlers.empty(); }
void operator()(TObject* sender, const TEventArgs& e) const
{
for(const TEventHandler& handler : _handlers)
{
handler(sender, e);
}
}
};
template< typename >
можно получить и тип результата функции, и типы всех ее параметров всего за одну частичную специализацию шаблона.template<typename TObject, typename TEventArgs>
class Event<std::function<void(TObject*, const TEventArgs& e)>>
std::function
здесь? Для чего ты обязываешь своего пользователя инстанцировать шаблон события именно таким образом?std::function
из параметров шаблона события.template< typename >
class Event;
template< typename TResult, typename... TArguments >
class Event<TResult ( TArguments... )> final
{
};
TResult
и TArguments
для определения оператора функционального вызова.#include <functional>
#include <string>
template <typename F>
struct HandlerTraits;
template <typename R, typename ...Args>
struct HandlerTraits<std::function<R(Args...)>>
{
using ReturnType = R;
using ArgTypes = std::tuple<Args...>;
static constexpr std::size_t ArgCount = sizeof...(Args);
template <std::size_t N>
using NthArg = std::tuple_element_t<N, ArgTypes>;
};
template <typename T>
void processEvent(T const& handler)
{
using Traits = HandlerTraits<T>;
static_assert(std::is_same_v<typename Traits::ReturnType, void>);
static_assert(Traits::ArgCount == 2);
static_assert(std::is_same_v<typename Traits::template NthArg<0>, std::string*>);
static_assert(std::is_same_v<typename Traits::template NthArg<1>, int const&>);
}
int main()
{
processEvent(std::function<void(std::string*, int const&)>{});
}