Home > Mobile >  How to conditionally get template type of multiple base class with multiple inheritance
How to conditionally get template type of multiple base class with multiple inheritance

Time:07-30

This is NOT a duplicate of link

Consider the following code:

#include <type_traits>

template <typename... Bases>
struct Overloads : public Bases... {};

template <typename T>
struct A {
  using AType = T;
};

template <typename T>
struct B {
  using BType = T;
};

template <typename T>
struct C {
  using CType = T;
};

template <typename OverloadsType>
struct Derived : public OverloadsType {
  
};

int main() {
    // OK
    static_assert(std::is_same_v<typename Derived<Overloads<A<int>, B<float>, C<char>>>::AType, int>);
    // OK
    static_assert(std::is_same_v<typename Derived<Overloads<A<int>, B<float>, C<char>>>::BType, float>);
    // OK
    static_assert(std::is_same_v<typename Derived<Overloads<A<int>, B<float>, C<char>>>::CType, char>);
    // ???
    static_assert(std::is_same_v<typename Derived<Overloads<B<float>, C<char>>>::AType, void>);
    
}

Demo: Link

For the last line, I need to detect that Derived<Overloads<B<float>, C<char>>> is NOT derived from A, so I want typename Derived<Overloads<B<float>, C<char>>>::AType to be void or something (it fails to compile)

How can I do this?

CodePudding user response:

My precise use case is: 1. Determine if Derived is derived from A<T> for some T. 2. If so, figure out that T.

With C 20 concepts, this isn't too difficult. You need a function that takes A<T> as a parameter. There need not be a function definition; we're just using template argument deduction. It will never be called:

template<typename T>
T getDerivedFromAType(A<T> const&); //Not implemented, since we will never call it.

Any type U for which getDerivedFromAType(u) works will either be one that is derived from A<T> or is convertible to an A<T>. That last one doesn't quite fit your needs, but it's more or less unavoidable. Regardless, we can build a concept out of it:

template<typename U>
concept IsDerivedFromA = requires(U u)
{
  getDerivedFromAType(u);
};

So long as nobody writes an overload of getDerivedFromAType, you're fine. This function ought to be in a detail namespace or have something else that lets people know that it is off-limits.

To get the actual T used by A... well, there's a reason why the function returned T. We simply need a using statement that calculates the return type of the function call:

template<IsDerivedFromA T>
using BaseAType = decltype(getDerivedFromAType(std::declval<T>()));

Notice that the template is guarded by our concept.

You could even make a bigger concept that weeds out the "convertible from" loophole:

template<typename U>
concept IsDerivedFromAAndNotConvertible =
  IsDerivedFromA<U> && std::derived_from<U, A<BaseAType<U>>>;
  • Related