I'm using a "traits" pattern where I have a base case expressed as a class template
template <class>
struct DoCache {
constexpr static bool value = false;
};
and I expect users to specialize for their types:
template <>
struct DoCache<MyType> {
constexpr static bool value = true;
static void write2Cache(MyType const&) { /* implementation */ }
static optional<MyType> readFromCache(string name) { /* implementation */ }
};
The typical use is to retrieve and use this as:
// Define a variable template
template <class T>
constexpr bool do_cache_v = DoCache<T>::value;
// Use the above trait in compile time branching:
if constexpr (do_cache_v<T>)
{
write2Cache(arg);
}
There's two problems I have with this code:
- A user is only indirectly enforced to provide a "value" member when specializing, let alone making it the proper value (i.e.
true). By indirectly I mean they'll get a bunch of compilation errors that one can only solve if they know the answer beforehand. - There's no way of "requiring" them to create the two needed methods, namely
write2CacheandreadFromCache, let alone having (const) correct types.
In some code-bases I've seen the considerations above being tackled by defining a generator macro like:
#define CACHABLE(Type, Writer, Reader) ...
- Is there a better way to it?
- Can concepts be used to restrict the way a specialization looks?
- Is there a C++17 compatible way?
an answer to any of the above is appreciated