Strong aliases for types similar to mp-units "downcasting facility" using only C++14

Viewed 48

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:

  1. downcast<T> resolves to an alias type if such a type exists for T, otherwise resolves to T.
  2. 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.

0 Answers
Related