Reputation: 2328
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 */ }
Upvotes: 1
Views: 357
Reputation: 2328
So, I worked around the conditional compilation in the macro by using a second template struct that can use enable_if
. Whenever I tried to directly put enable_if
in the template specialization created by the macro, the compiler would complain.
Advantages:
Disadvantages:
If someone finds a nicer approach, I will accept their answer. Until then, here is what I did:
// The type-class
template <class T> struct Comp {
static auto do_f(T&) -> void = delete;
};
// Helper for auto-deriving
template <class T> struct DerivedComp {
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(); }
};
// Macro to automatically derive an implementation
#define DERIVE_COMP(T) \
template <> struct Comp<T> { \
static auto do_f(T& t) -> void { DerivedComp<T>::do_f(t); } \
};
Upvotes: 0