Убедитесь, что класс не наследуется от двух интерфейсов - PullRequest
1 голос
/ 11 июля 2020

У меня такая проблема. Есть фреймворк, который мы разрабатываем и используем. У нас есть несколько интерфейсов, которые необходимо реализовать пользователю этого фреймворка. Я хочу убедиться, что два из этих интерфейсов никогда не могут быть реализованы в одном классе. вот пример

class A{
  void a() = 0;
};
class B{
  void b() = 0;
};

class C: public A, public B { // This should give error
};
class D: public A{ // OK
};

До сих пор я думал, может быть, я могу использовать static_assert и std::is_convertible, но я не могу понять, как это сделать.

Изменить: Я не знаю, кто будет писать производные классы, поэтому я хочу, чтобы они были в базовых интерфейсах, если это возможно. В основном предположим, что у меня нет доступа к производным классам, потому что они не входят в нашу базу кода.

Спасибо.

1 Ответ

2 голосов
/ 11 июля 2020

Напишите собственный трейт следующим образом:

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");
};
...