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_ifs 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 */ }