继承通用成员函数
Inheriting generic member functions
我正在尝试将模板化成员函数的定义和声明从基础 class 转移到派生 classes。要注意的是,这些函数中的某些行为取决于 class,基本上是静态多态性。我被推荐使用 CRTP,它在大多数情况下都很好用。
但是,如果我想从已经从我的 CRTP 基础 class 继承的 class 继承,我有一个问题。考虑以下代码:
template<typename Derived>
struct CRTP
{
template<typename TypeRHS>
Derived& operator+=(const TypeRHS& rhs)
{
// do something
return static_cast<Derived&>(*this);
}
};
template<typename T>
struct Derived : public CRTP<Derived<T>> {};
template<typename T>
struct DerivedDerived : public Derived<T> {};
如果我在 DerivedDerived<T>
上调用 +=
,它会 return 一种 Derived<T>
。有什么办法可以解决这个问题。我只是想避免必须 redeclare/redefine 所有 class 中的所有成员函数。就自由函数而言,我只是将它们模板化,但成员函数已被证明是一个问题。
我已经根据 Brian 的建议更新了我的问题。请注意,多重继承会导致关于应该调用哪个函数的歧义 - 来自 CRTP<DerivedDerived<T>>
的函数或来自 Derived<T>
的函数:
template<typename T>
struct DerivedDerived : public Derived<T>, public CRTP<DerivedDerived<T>> {};
您需要一个派生自 Derived 的 CRTP 以供 DerivedDerived 使用
template<typename T>
struct CRTP
{
template<typename TypeRHS>
T& operator+=(const TypeRHS& rhs)
{
// do something
return static_cast<T&>(*this);
}
};
template<typename T>
struct Derived : public CRTP<Derived<T>> {
};
template<typename T>
struct CRTPForDerived : public Derived<T>
{
template<typename TypeRHS>
T& operator+=(const TypeRHS& rhs)
{
// do something
return static_cast<T&>(*this);
}
};
template<typename T>
struct DerivedDerived : public CRTPForDerived<DerivedDerived<T> >
{};
对于算术运算符的特定情况,您可以通过在 class/struct 之外声明运算符来解决该问题。在这种情况下,不需要 CRTP 构造:
#include <type_traits>
// Replaces template<typename> struct CRTP;
struct MyOperatorsBase {
};
template<typename T>
struct Derived : public MyOperatorsBase {
};
template<typename T>
struct DerivedDerived : public Derived<T> {
};
// Overload "a += b" defined only if "a" derives from MyOperatorsBase.
template<typename RetType, typename RhsType>
std::enable_if_t<std::is_base_of_v<MyOperatorsBase,RetType>,RetType&> operator +=(RetType& lhs, const RhsType& rhs) {
// do something.
return lhs; // no downcasting static_cast needed, which is nice
}
Live demo
对于未来的读者,我能想到的最通用和模块化的解决方案实际上是将我需要在 DerivedDerived
中继承的相关部分从 Derived
分离到它们单独的 class ,然后 Derived
可以继承这些以及 CRTP class,然后可以对 DerivedDerived
执行相同的操作,有效地将两者置于层次结构中的同一级别。
我正在尝试将模板化成员函数的定义和声明从基础 class 转移到派生 classes。要注意的是,这些函数中的某些行为取决于 class,基本上是静态多态性。我被推荐使用 CRTP,它在大多数情况下都很好用。 但是,如果我想从已经从我的 CRTP 基础 class 继承的 class 继承,我有一个问题。考虑以下代码:
template<typename Derived>
struct CRTP
{
template<typename TypeRHS>
Derived& operator+=(const TypeRHS& rhs)
{
// do something
return static_cast<Derived&>(*this);
}
};
template<typename T>
struct Derived : public CRTP<Derived<T>> {};
template<typename T>
struct DerivedDerived : public Derived<T> {};
如果我在 DerivedDerived<T>
上调用 +=
,它会 return 一种 Derived<T>
。有什么办法可以解决这个问题。我只是想避免必须 redeclare/redefine 所有 class 中的所有成员函数。就自由函数而言,我只是将它们模板化,但成员函数已被证明是一个问题。
我已经根据 Brian 的建议更新了我的问题。请注意,多重继承会导致关于应该调用哪个函数的歧义 - 来自 CRTP<DerivedDerived<T>>
的函数或来自 Derived<T>
的函数:
template<typename T>
struct DerivedDerived : public Derived<T>, public CRTP<DerivedDerived<T>> {};
您需要一个派生自 Derived 的 CRTP 以供 DerivedDerived 使用
template<typename T>
struct CRTP
{
template<typename TypeRHS>
T& operator+=(const TypeRHS& rhs)
{
// do something
return static_cast<T&>(*this);
}
};
template<typename T>
struct Derived : public CRTP<Derived<T>> {
};
template<typename T>
struct CRTPForDerived : public Derived<T>
{
template<typename TypeRHS>
T& operator+=(const TypeRHS& rhs)
{
// do something
return static_cast<T&>(*this);
}
};
template<typename T>
struct DerivedDerived : public CRTPForDerived<DerivedDerived<T> >
{};
对于算术运算符的特定情况,您可以通过在 class/struct 之外声明运算符来解决该问题。在这种情况下,不需要 CRTP 构造:
#include <type_traits>
// Replaces template<typename> struct CRTP;
struct MyOperatorsBase {
};
template<typename T>
struct Derived : public MyOperatorsBase {
};
template<typename T>
struct DerivedDerived : public Derived<T> {
};
// Overload "a += b" defined only if "a" derives from MyOperatorsBase.
template<typename RetType, typename RhsType>
std::enable_if_t<std::is_base_of_v<MyOperatorsBase,RetType>,RetType&> operator +=(RetType& lhs, const RhsType& rhs) {
// do something.
return lhs; // no downcasting static_cast needed, which is nice
}
Live demo
对于未来的读者,我能想到的最通用和模块化的解决方案实际上是将我需要在 DerivedDerived
中继承的相关部分从 Derived
分离到它们单独的 class ,然后 Derived
可以继承这些以及 CRTP class,然后可以对 DerivedDerived
执行相同的操作,有效地将两者置于层次结构中的同一级别。