The mp-units library has a function they call the "downcasting facility" documented here
This allows long template specializations to be given short aliases which can be automatically resolved by the compiler simply by inheriting a CRTP template.
The very basic version of this is below:
template<class BaseType>
struct downcast_base {
using downcast_base_type = BaseType;
friend auto downcast_guide(const downcast_base&); // declaration only (no implementation)
};
template<typename T>
concept has_downcast_guide = requires(T t) { downcast_guide(t); };
template<class Target, class Base>
struct downcast_child : Base
{
friend auto downcast_guide(const typename Base::downcast_base&) { return Target{}; }
};
template<class Base>
struct downcast_impl {
using type = Base;
};
template<class Base>
requires(has_downcast_guide<Base>)
struct downcast_impl<Base>
{
using type = decltype(downcast_guide(std::declval<Base>()));
};
template<class T>
using downcast = typename detail::downcast_impl<T>::type;
template<typename T>
concept Downcastable =
requires { typename T::downcast_base_type; } &&
std::derived_from<T, detail::downcast_base<typename T::downcast_base_type>>;
template<CONCEPT(Downcastable) T>
using downcast_base_t = typename T::downcast_base_type;
The idea here is that if a type inheriting from downcast_child<T> exists, downcast<T> will resolve to that type, otherwise it will resolve to type T.
The problem with this, is that it requires the concept has_downcast_guide to determine if an alias type exists, and I need to target an environment that only supports C++14 (embedded ARM).
Unfortunately, since this relies on return type deduction for downcast_guide, I apparently can't use SFINAE to determine if the guide exists for a particular as described here
Is there an alternate way of resolving an alias similar to this using only C++14 features? I'm OK with the process of registering an alias requiring an extra step, but I do need the following functionality:
- downcast<T> resolves to an alias type if such a type exists for T, otherwise resolves to T.
- downcast_base<T> resolves to a base type if T is an alias type, otherwise resolves to T.
It seems like something could be done with explicit specialization of a base template, but I'm having trouble figuring out how to structure it to enable it to resolve both ways.