首页 > 解决方案 > 通过 CRTP 简化类相互扩展的 API

问题描述

我想编写通过( CRTP)扩展多个类的类。

我只能Extension<Base<Extension>> my_object;去上班了。

我想要的api是:Extension<Base> my_object;

如何使这个 api 工作?

谢谢。

测试(代码也在godbolt.org):

#include <iostream>

template <template<typename...> class Extension>
class Base1 : public Extension<Base1<Extension>> {
public:
    static void beep() { std::cout << "Base1 "; }
};

template <class Plugin>
class Extension1 {
public:
    Extension1() : plugin_(static_cast<Plugin*>(this)) {}
    void beep() {
        plugin_->beep();
        std::cout << "Extension1\n";
    }
private:
    Plugin* plugin_;
};

template <template<typename...> class Plugin>
class Extension2 {
public:
    Extension2() : plugin_(static_cast<Plugin<Extension2>*>(this)) {}
    void beep() {
        plugin_->beep();
        std::cout << "Extension2\n";
    }
private:
    Plugin<Extension2>* plugin_;
};

int main() {
    // This works.
    Extension1<Base1<Extension1>>b;
    b.beep();
    // This doesn't work.
    Extension2<Base1> c;
    c.beep();
    return 0;
}

标签: c++templatesapi-designcrtptemplate-templates

解决方案


一个问题是模板参数与具有Extension2的签名不匹配Base1。另一个是Extension2与预期的参数类型不匹配Base1

如果您将 的定义更改为Extension2正确地接受Base1,它本身仍然不是要传递给的候选人Base1。您可以使用与Base1预期匹配的内部模板类来解决此问题。这个内部类看起来很像Extension1.

template <template<template<typename...> class> class Plugin>
class Extension2 {
    template <class P>
    struct Inner {
        Inner () : plugin_(static_cast<P *>(this)) {}
        void beep() { plugin_->beep(); }
    private:
        P* plugin_;
    };
public:
    Extension2() {}
    void beep() {
        plugin_.beep();
        std::cout << "Extension2\n";
    }
private:
    Inner<Plugin<Inner>> plugin_;
};

推荐阅读