Перегрузка операторов при наследовании вариационных шаблонов - PullRequest
0 голосов
/ 28 ноября 2018

Представьте себе код, подобный следующему:

struct Foo
{
    int foo{0};
};

Foo operator+(const Foo& lhs, const Foo& rhs)
{
    Foo ret;
    ret.foo = lhs.foo + rhs.foo;
    return ret;
}

struct Bar
{
    int bar{0};
};

Bar operator+(const Bar& lhs, const Bar& rhs)
{
    Bar ret;
    ret.bar = lhs.bar + rhs.bar;
    return ret;
}

template<typename... Ts>
struct Fooz : public Ts...
{

};

template<typename... Ts>
Fooz<Ts...> operator+(const Fooz<Ts...>& lhs, const Fooz<Ts...>& rhs)
{
    // how can you call base class's operator+ here?
}

int main(int argc, char **argv)
{
    Fooz<Foo,Bar> fooz1{1,1}; // fooz1.foo == 1; fooz1.bar == 1;
    Fooz<Foo,Bar> fooz2{2,2}; // fooz2.foo == 2; fooz2.bar == 2;

    // auto fooz3 = fooz1 + fooz2 // fooz3.foo == 3; fooz3.bar == 3;
    return 0;
}

Здесь необходимо вариативное наследование, так как я хочу, чтобы все переменные-члены из базовых структур наследовались в классе вариадики (см. main).

Вопрос в том, можно ли вызвать operator+ базовую структуру внутри FooBar функции operator+?

Любая помощь приветствуется!

Ответы [ 2 ]

0 голосов
/ 28 ноября 2018

Поскольку вопрос помечен C ++ 11, в качестве альтернативы @PiotrSkotnicki, стоит упомянуть, что для достижения этого также можно использовать старый добрый рекурсивный пилинг переменных параметров:

template<typename T, typename... Rest>
struct Aggregate_add_impl {
  static void add(T& dst, const T& lhs, const T& rhs) {
    // intentional no-op
  }  
};

template<typename T, typename U, typename... Rest>
struct Aggregate_add_impl<T, U, Rest...> {
  static void add(T& dst, const T& lhs, const T& rhs) {
      U& dst_as_u = static_cast<U&>(dst);
      const U& l_as_u = static_cast<const U&>(lhs);
      const U& r_as_u = static_cast<const U&>(rhs);

      dst_as_u = l_as_u + r_as_u;
      Add_impl<T,Rest...>::add(dst, lhs, rhs);
  }
};

template <typename... Ts>
Fooz<Ts...> operator+(const Fooz<Ts...>& lhs, const Fooz<Ts...>& rhs)
{    
    Fooz<Ts...> ret;
    Aggregate_add_impl<Fooz<Ts...>, Ts...>::add(ret, lhs, rhs);
    return ret;
}

Это также имеет то преимущество, что Fooz не требуется, чтобы его можно было использовать для агрегирования (но оно ДОЛЖНО быть по умолчанию или копируемым).

Стоит отметить, что реализация operator+= таким способом на самом деле немногоПроще, так что если у вас есть и +, и +=, просто используйте позднее.

0 голосов
/ 28 ноября 2018

В , если Fooz является агрегатным типом, как в вопросе, вы можете скопировать-инициализировать список Fooz в ( список ) - инициализироватькаждый прямой базовый класс с индивидуальными результатами:

template <typename... Ts>
Fooz<Ts...> operator+(const Fooz<Ts...>& lhs, const Fooz<Ts...>& rhs)
{    
    return { {static_cast<const Ts&>(lhs) + static_cast<const Ts&>(rhs)}... };
}

DEMO

In , вы 'd дополнительно нужно предоставить конструктор:

Fooz(const Ts&... ts) : Ts{ts}... {}
...