CRTP 在调用链中的用法

Usage of CRTP in a call chain

本文关键字:用法 调用 CRTP      更新时间:2023-10-16

在我的小部件库中,我想实现某种调用链来初始化一个用户提供的 VIEW 类,该类可能(!) 派生自另一个添加一些附加功能,如下所示:

#include <iostream>
template<typename VIEW>
struct App
{
    VIEW view;
    void init() {view.initialize(); }
};
template<typename DERIVED>
struct SpecializedView
{
    void initialize()
    {
        std::cout << "SpecializedView" << std::endl;
        static_cast<DERIVED*>(this)->initialize();
    }
};
struct UserView : SpecializedView<UserView>
{
    void initialize() {std::cout << "UserView" << std::endl; }
};
int _tmain(int argc, _TCHAR* argv[])
{
    // Cannot be altered to: App<SpecializedView<UserView> > app;
    App<UserView> app; 
    app.init();
    return 0;
}

是否有可能实现某种调用链(如果用户提供的 VIEW 类派生自"SpecializedView"),以便输出将是:

console output:
SpecializedView
UserView

当然,使用派生自的类型实例化变量应用程序很容易但是此代码隐藏在库中,不应更改。换句话说:库代码应仅获取用户派生类型作为参数。

您可以编写另一个函数,该函数在类和基类(如果存在)上调用initialize(),并定义一个initialize()方法:

template <class T>
void callInitialize(T* t) {
    t->initialize();
    IF_EXISTS(base_class<T>::bc::initialize)
        callInitialize<base_class<T>::bc>(t);
}

当然,调用的顺序可以颠倒。

请参阅是否可以编写模板来检查函数是否存在? 关于IF_EXISTS的实现 。此外,base_class<T>不是标准结构,此答案表明这不能自动完成。 语义如下所示:

template<T>
struct base_class<T> {
    typedef void bc;
};
template<>
struct base_class<UserView> {
    typedef SpecializedView<UserView> bc;
};

也许您的框架允许半自动的方式来执行此操作。