实现模板化模板方法

Implementing templated template method

本文关键字:模板方法 实现      更新时间:2023-10-16

注意:以下问题是关于模板方法设计模式C++函数模板的。为了区分两者,我在引用设计模式时使用斜体,在引用C++模板时使用粗体

模板方法模式的思想是使算法的各部分可交换。这通常是通过继承实现的,其中子类提供插入基类算法的具体实现。但是,如果钩子方法需要是模板,这将不起作用,因为的模板

class Base
{
public:
    // This is the template method
    template <typename T>
    void doSomething(T input)
    {
        //...
        auto converted = ConvertInput(input);
        //...
        std::cout << converted;
    }
protected:
    //compile error "member function templates cannot be virtual"
    template <typename T>
    virtual T ConvertInput(T input) = 0;
};
class Derived : public Base
{
protected:
    template <typename T>
    T ConvertInput(T input)
    {
        return 2 * input;
    }
};
int main()
{
    Derived d;
    d.doSomething(3);
}

有没有一种方法可以实现使用函数模板钩子的模板方法

我对在任何地方使用Base类作为类型都不感兴趣。我将始终使用具体的特定类型来实现最大限度的编译时优化。因此,这个问题的另一个公式是:如何创建几个具有函数模板的类Derived-1 .. Derived-n,这些类在实现中共享一个公共代码框架?

听起来像是CRTP的一个很好的用例。将Base定义为类模板,并将从中派生的类型作为模板参数。在Base的方法中,您可以归结为派生类型:

template<typename Derived>
struct Base
{
    // This is the template method
    template <typename T>
    void doSomething(T input)
    {
        //...
        auto converted = static_cast<Derived*>(this)->ConvertInput(input);
        //...
        std::cout << converted << std::endl;
    }
};

然后定义派生类型,例如:

struct Square : Base<Square>
{
    template<typename T>
    auto ConvertInput(T t)
    {
        return t*t;
    }
};
struct Sum : Base<Sum>
{
    template<typename T>
    auto ConvertInput(T t)
    {
        return t+t;
    }
};

其用法相当琐碎:

Square sq;
Sum sum;
sq.doSomething(3);
sum.doSomething(3);

实时演示

CRTP通过将Base作为模板来解决您的问题。

如果T来自有限集,或者转换是非丛式的,则类型擦除可以工作。

如果是有限集,请键入擦除所有派生的虚拟方法。如果是公共属性,请键入擦除该属性并虚拟化作用于它的方法。或者是一个混合物。

否则,Base可以具有将操作作为函数对象的模板方法(使用模板operator()(,而不是使用virtual来查找它。Derived将模板化的操作作为参数传递给Base方法。这基本上是没有CRTP的CRTP。