Overloading by concept without concepts in C++ part II
In the previous post, we’ve seen how to select an overload from a set of functions based on concepts matching the arguments, without actual concept support in the C++ language. The described solution allows a library to define a single set of overloads.
However, how to allow the client to override the library provided overload for a given concept? Simply adding a specialization would result in ambiguous function calls. If not today, probably later, when the library changes - making the solution hard to maintain.
A conflict free solution simply adds an indirection:
- If user defined overload exists, call that
- Otherwise call the library defined function
This clearly models what we want to achieve. This is how it looks in code:
template <typename, typename = void> struct CustomF {
CustomF() = delete; // detection will use is_constructible
};
template <typename, typename = void> struct BuiltinF; // default case undefined
// Specializations for supported concepts as shown before follow...
template <typename T> struct F {
using type = std::conditional_t<
std::is_constructible<CustomF<T>>::value,
CustomF<T>,
BuiltinF<T>
>;
};
The type
member of F
will be either the user defined custom logic (if the type is constructible),
or the built-in logic. The wrapper that hides the invocation remains the same:
template <typename T>
void f(const T& t) { detail::F<T>::f(t); }
That’s it! Now clients can easily add CustomF
specializations, without risking conflicts
with the present or future specializations of BuiltinF
.
This is the system that the binlog serializer library, mserialize uses.