可变参数模板继承中的运算符重载

时间:2018-11-28 19:29:46

标签: c++11 operator-overloading c++14 c++17 variadic-templates

想象这样的代码:

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+的{​​{1}}函数中调用基本结构的FooBar

感谢您的帮助!

2 个答案:

答案 0 :(得分:5)

中,如果Fooz是问题中的聚合类型,则可以将Fooz复制列表初始化到( list )初始化每个直接基类都有各自的结果:

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

中,您还需要提供一个构造函数:

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

答案 1 :(得分:2)

由于该问题被标记为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+=实际上要简单得多,因此,如果同时拥有++=,则只需实现后者即可。

相关问题