使用具有相同成员函数名称的 CRTP

Using CRTP with same member function name

本文关键字:函数 CRTP 成员      更新时间:2023-10-16

当我看到使用的 CRTP 模式时,似乎在基类型中调用的函数名称总是指向派生类型中不同名称的实现函数(例如:foo() 在基中使调用static_cast<DerivedType*>(this)->foo_implementation();

有没有办法使用相同的函数名称实现 CRTP 模式?我有一个更长的继承链,其中函数可能在链的第一级中没有具体的实现,因此必须使用不同的函数名称不是很干净/可读。

我想要类似以下内容的东西:

template <typename SecondType>
struct FirstType {
    void foo() {
        static_cast<SecondType*>(this)->foo();
    }
};
template <typename ThirdType>
struct SecondType : FirstType<SecondType> {
    void foo() {
        static_cast<ThirdType*>(this)->foo();
    }
};
struct ThirdType : SecondType<ThirdType> {
    void foo() {
        // Concrete implementation here
    }
};

当然,编译器不会抱怨这一点,但我想它会导致隐式 vtable 查找(尽管没有出现 virtual 关键字),从而违背了使用 CRTP 的目的。

您可以很好地对两个函数使用相同的名称,它将正常工作。

使用不同名称的优点是,未能在派生类中实现函数将导致编译器错误,而不是在运行时无限递归和可能的堆栈溢出。

为什么不断言成员函数不同?从 ThirdType 中删除 foo() 会给你一个编译错误,并显示一条很好的消息。

#include <type_traits>
template <typename SecondType>
struct FirstType {
    void foo() {
        static_assert(
            !std::is_same<
                decltype(&FirstType::foo),
                decltype(&SecondType::foo)
             >::value,
            "SecondType must implement method 'void foo()'");
        static_cast<SecondType*>(this)->foo();
    }
};
template <typename ThirdType>
struct SecondType : FirstType<SecondType<ThirdType>> {
    void foo() {
        static_assert(
            !std::is_same<
                decltype(&SecondType::foo),
                decltype(&ThirdType::foo)
             >::value,
            "ThirdType must implement method 'void foo()'");
        static_cast<ThirdType*>(this)->foo();
    }
};
struct ThirdType : SecondType<ThirdType> {
    void foo() {
        // Concrete implementation here
    }
};
template class SecondType<ThirdType>;
template class FirstType<SecondType<ThirdType>>;