Напишите собственный трейт следующим образом:
template<typename Derived, typename... BaseCandidates>
struct has_no_base;
template<typename Derived>
struct has_no_base<Derived>
: std::true_type { };
template<typename Derived, typename BaseFirst, typename... BasesRest>
struct has_no_base<Derived, BaseFirst, BasesRest...>
: std::conditional_t<
std::is_base_of<BaseFirst, Derived>,
std::true_type,
has_no_base<Derived, BasesRest...>
> { };
template<typename Derived, typename... PossibleBases>
struct has_only_one_base;
template<typename Derived>
struct has_only_one_base<Derived>
: std::false_type { };
template<typename Derived, typename Base>
struct has_only_one_base<Derived, Base>
: std::conditional_t<
std::is_base_of_v<Base, Derived>,
std::true_type,
std::false_type
> { };
template<typename Derived, typename BaseFirst, typename... BasesRest>
struct has_only_one_base<Derived, BaseFirst, BasesRest...>
: std::conditional_t<
std::is_base_of_v<BaseFirst, Derived>,
has_no_base<Derived, BasesRest...>,
has_only_one_base<Derived, BasesRest...>
> { };
И используйте его так:
class MyClass : public A, public B
{
static_assert(has_only_one_base<MyClass, A, B>::value, "Error");
};
Более того, если вы разработчик этого фреймворка, вы можете предоставить некоторые проверьте трейт:
template<typename Type>
using is_valid_class = has_only_one_base<Type, IFirst, ISecond, ... ILast>;
И используйте его:
class MyClass : public A, public B
{
static_assert(is_valid_class<MyClass>::value, "Error");
};