You could create some type traits to help out.
First one to test if a type is really an A type:
#include <type_traits> template<class T> struct is_A_type { static std::false_type test(...); template<template<class...> class U, class... V, std::enable_if_t<std::is_same_v<U<V...>, A<V...>>, int> = 0> static std::true_type test(const U<V...>&); static constexpr bool value = decltype(test(std::declval<T>()))::value; }; template<class T> inline constexpr bool is_A_type_v = is_A_type<T>::value;
Then a trait to get the type of the first template parameter:
template<class T> struct first_type { static void test(...); template<template<class...> class U, class F, class... V> static auto test(const U<F, V...>&) -> F; using type = decltype(test(std::declval<T>())); }; template<class T> using first_type_t = typename first_type<T>::type;
These traits could then be used like so:
template<class A_Type> class B : public A_Type { static_assert(is_A_type_v<A_Type>, "A_Type must be an A type"); using T = first_type_t<A_Type>; T j; };
A<T,U>instances be accepted asA_Types inB<A_Type>?