Вызов конструктора базовых классов миксина на основе количества аргументов - PullRequest
1 голос
/ 21 января 2020

У меня есть два набора базовых классов mixin, которые следуют следующей схеме

// base class taking one contructor argument
struct OneArgBase
{
  const double x;

  template<typename T>
  OneArgBase(const T & t) :
    x(t.x)
  {}
};

// base class taking two constructor arguments
struct TwoArgBase
{
  const double y;

  template<typename T, typename U>
  TwoArgBase(const T & t, const U & u) :
    y(t.y + u.y)
  {}
 };

Из этих базовых классов я получаю два набора классов mixin

template<typename ... Mixins>
struct OneArgMix : Mixins...
{
  template<typename T>
  OneArgsMix(const T & t) :
    Mixins(t)...
  {}
};

template<typename ... Mixins>
struct TwoArgMix : Mixins...
{
  template<typename T, typename U>
  TwoArgsMix(const T & t, const U & u) :
    Mixins(t, u)...
  {}
};

Проблема, с которой я сталкиваюсь Теперь я хочу передать классы, следующие шаблону OneArgBase, в TwoArgMix

using Mix = TwoArgMix<TwoArgBase, OneArgBase>;

template<typename ... Mixins>
struct TwoArgMix : Mixins...
{
  template<typename T, typename U>
  TwoArgsMix(const T & t, const U & u) :
    Mixins(t, u)... // if Mixins is TwoArgBase
    Mixins(t)... // if Mixins is OneArgBase
  {}
};

, но понятия не имею, как два пишут конструктор TwoArgMix таким образом, что if передает только первый параметр шаблона в базу Mixin. классы, которые следуют шаблону OneArgMix. Если возможно, я бы хотел избежать записи фиктивных аргументов в конструктор OneArgMix, потому что эти классы необходимы и для OneArgMix.

Ответы [ 3 ]

3 голосов
/ 21 января 2020

Все проблемы в программировании можно решить, добавив еще один уровень косвенности.

Нам нужно условно игнорировать второй аргумент, если он не конструктивен. Один из способов сделать это - заключить каждый миксин в другой тип, который условно игнорирует его второй аргумент:

template <typename M>
struct WrappedMixin : M
{
    template <typename T, typename U>
    WrappedMixin(T const& t, U const& u)
       : WrappedMixin(t, u, std::is_constructible<M, T const&, U const&>{})
    { }

private:
    template <typename T, typename U>
    WrappedMixin(T const& t, U const& u, std::true_type /* yes, use both */)
      : M(t, u)
    { }

    template <typename T, typename U>
    WrappedMixin(T const& t, U const&, std::false_type /* no, just one */)
      : M(t)
    { }
};

И теперь наш основной конструктор прост: вместо этого мы просто наследуем от упакованных:

template<typename ... Mixins>
struct TwoArgMix : WrappedMixin<Mixins>...
{
  template<typename T, typename U>
  TwoArgsMix(const T & t, const U & u)
    : WrappedMixin<Mixins>(t, u)...
  { }
};
2 голосов
/ 21 января 2020

С фабрикой вы можете сделать что-то вроде:

template <typename> struct Tag{};

template<typename T, typename U>
OneArgBase Create(Tag<OneArgBase>, const T& t, const U&)
{
    return OneArgBase(t);
}

template<typename T, typename U>
TwoArgBase Create(Tag<TwoArgBase>, const T& t, const U& u)
{
    return TwoArgBase(t, u);
}

template<typename ... Mixins>
struct TwoArgsMix : Mixins...
{
  template<typename T, typename U>
  TwoArgsMix(const T & t, const U & u) :
    Mixins(Create(Tag<Mixins>{}, t, u))...
  {}
};

Демо

0 голосов
/ 21 января 2020

Вы можете попытаться использовать частично указанный шаблон.

Что-то вроде:

template<typename twoarg>
struct TwoArgMix<twoarg, OneArgBase>: ...

Это будет конкретная c реализация с OneArgBase в качестве второго параметра шаблона.

...