继承泛型成员函数

Inheriting generic member functions

本文关键字:函数 成员 泛型 继承      更新时间:2023-10-16

我正在尝试将模板化成员函数的定义和声明从基类转移到派生类。问题是这些函数中的一些行为取决于类,基本上是静态多态性。我被建议使用 CRTP,它在大多数情况下效果很好。但是,如果我想从已经从我的 CRTP 基类继承的类继承,我遇到了问题。请考虑以下代码:

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>上调用+=,它将返回一种Derived<T>。有没有办法解决这个问题。我只是想避免在所有类中重新声明/重新定义所有成员函数。就自由函数而言,我刚刚模板化了这些函数,但成员函数已被证明是一个问题。

我已经用布莱恩的建议更新了我的问题。请注意,多重继承会导致应该调用哪个函数的歧义 - 一个来自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> > 
{};

对于算术运算符的特定情况,您可以通过在类/结构之外声明运算符来解决此问题。在这种情况下,不需要 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
}

现场演示

对于未来的读者,我能想到的最通用和模块化的解决方案实际上是将我需要在DerivedDerived继承的相关部分从Derived分离到它们的单独类中,然后Derived可以继承这些以及 CRTP 类,然后可以做同样的事情来DerivedDerived有效地将两者放在层次结构中的同一级别。