可变参数模板继承中的运算符重载
Operator overloading in variadic template inheritance
想象一下这样的代码:
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;
}
此处需要可变参数继承,因为我希望将基本结构中的所有成员变量继承到可变参数 class(参见 main
)。
问题是:是否可以在 FooBar
的 operator+
函数中调用基本结构的 operator+
?
感谢任何帮助!
在c++17中,如果Fooz
是问题中的聚合类型,可以copy-list-initialize Fooz
to (list)-用单独的结果初始化每个直接基class:
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)}... };
}
在 c++14 中,您还需要提供一个构造函数:
Fooz(const Ts&... ts) : Ts{ts}... {}
由于问题被标记为 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+=
实际上要简单得多,所以如果您同时拥有 +
和 +=
,只需实现后者即可。
想象一下这样的代码:
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;
}
此处需要可变参数继承,因为我希望将基本结构中的所有成员变量继承到可变参数 class(参见 main
)。
问题是:是否可以在 FooBar
的 operator+
函数中调用基本结构的 operator+
?
感谢任何帮助!
在c++17中,如果Fooz
是问题中的聚合类型,可以copy-list-initialize Fooz
to (list)-用单独的结果初始化每个直接基class:
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)}... };
}
在 c++14 中,您还需要提供一个构造函数:
Fooz(const Ts&... ts) : Ts{ts}... {}
由于问题被标记为 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+=
实际上要简单得多,所以如果您同时拥有 +
和 +=
,只需实现后者即可。