【问题标题】:Implementing templated template method实现模板化模板方法
【发布时间】:2016-10-16 20:39:55
【问题描述】:

注意:以下问题是关于Template Method Design PatternC++ 函数模板。为了区分两者,我将在引用设计模式时使用 斜体,在引用 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。使BaseDerived 作为模板参数。通过static_cast&lt;D*&gt;(this)-&gt;ConvertInput拨打ConvertInput
  • T 使用的类型集是否有任何限制?
  • @Yakk 是的,但只有隐含的。例如。其中一个实例需要使用迭代器,它可以是任何东西。
  • @nico 迭代可以被类型擦除。 ;)

标签: c++ templates design-patterns template-method-pattern


【解决方案1】:

听起来像是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);

live demo

【讨论】:

  • 谢谢。我已经考虑过这个方向,这绝对是一个可能的解决方案。我也会对不需要将 Base 设为类模板的解决方案感兴趣。
  • CRTP 的 +1:没有读过去。如果帖子的其余部分让您感到困惑,请阅读有关 CRTP 的内容,您的问题非常适合。
【解决方案2】:

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

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多