I have written the following classes
#include <tuple>
class AbstractEvent
{
public:
using ID = int;
public:
virtual ~AbstractEvent() = default;
ID id() const { return id_; }
protected:
explicit AbstractEvent(ID id) : id_(id) {}
private:
ID id_;
};
template <AbstractEvent::ID ID_>
class Event : public AbstractEvent
{
public:
static constexpr auto kID = ID_;
Event() : AbstractEvent(kID) {}
};
template <typename T, typename ... ARGS>
class BasicEvent;
template <AbstractEvent::ID ID_, typename ... ARGS>
class BasicEvent<Event<ID_>, ARGS...> : public Event<ID_>
{
public:
explicit BasicEvent(ARGS... args) : _args(std::move(args)...) {}
~BasicEvent() = default;
template <unsigned int INDEX_ = 0>
inline const auto& arg() const
{
return std::get<INDEX_>(_args);
}
template <unsigned int INDEX_ = 0>
inline auto& arg()
{
return std::get<INDEX_>(_args);
}
private:
std::tuple<ARGS...> _args;
};
struct Events
{
enum : AbstractEvent::ID
{
Event1ID,
Event2ID,
};
using Event1 = Event<Event1ID>;
using Event2 = Event<Event2ID>;
};
My goal was to special the BasicEvent template so that I can pass either an "event ID" value or an Event class to it like so
class Event1 : public BasicEvent<Events::Event1ID> {};
or
class Event1 : public BasicEvent<Events::Event1> {};
However, the first example (using the ID) results in the following compile error on CLang:
template argument for template type parameter must be a type
and on GCC
type/value mismatch at argument 1 in template parameter list for 'template<class T, class ... ARGS> class BasicEvent'
This doesn't make sense to me. If I specialize the BasicEvent class to take a value, shouldn't the BasicEvent<Event<ID_>, ARGS...> match the template <typename T, typename ... ARGS> class BasicEvent; template?