I want to bring something like type-classes to my project using templates. I also want to be able to generate standard-implementations with a macro, but only if a method is implemented in the class implementing the type-class.
To be more specific, I have a type-class Comp<T>
, which has several methods. Assume it only has do_f
. I want to be able to implement do_f
manually, or call a DERIVE
macro, that automatically calls T::f
if T
has a method f
or do nothing if T
has no f
.
So the code I have looks like this:
template <typename T> struct Comp {
static auto do_f(T&) -> void = delete;
};
#define HAS_METHOD(T, f) ... // works already
#define DERIVE(T) /
template<> struct Comp<T> { /
static auto do_f(T &t) -> void { /
/* Here I'd like to call T::f iff it exists */ /
/* I am thinking about something like: */ /
#if (HAS_METHOD(T, f)) /
t.f(); /
#endif /
} /
};
I could then use this macro like this:
struct Foo { auto f() -> void { } };
struct Bar { };
struct Baz { auto g() -> void { } };
// Generate Comp<Foo>, where do_f calls f
DERIVE(Foo)
// Generate Comp<Bar>, where do_f does nothing
DERIVE(Bar)
// Hand-implement Comp<Baz>
template<> struct Comp<Baz> {
static auto do_f(Baz& b) -> void { b.g(); }
}
Based on the suggestion by Alessandro Teruzzi, I tried to use std::enable_if
, but so far it only works in the generic Comp<T>
. I would like to keep Comp<T>
with only the = delete
and have the conditional compilation in the DERIVE
macro. If I move the enable_if
s into the macro, I get errors that enable_if
cannot disable the functions.
Here is what it currently looks like
template<typename T> struct Comp {
template<std::enable_if_t<HAS_METHOD(T, f), bool> = true>
static auto do_f(T&) -> void {}
template<std::enable_if_t<!HAS_METHOD(T, f), bool> = true>
static auto do_f(T& t) -> void { t.f(); }
};
#define DERIVE(T) \
template<> struct Comp<T> { /* set some other stuff */ }