Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/templates/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 实现模板化模板方法_C++_Templates_Design Patterns_Template Method Pattern - Fatal编程技术网

C++ 实现模板化模板方法

C++ 实现模板化模板方法,c++,templates,design-patterns,template-method-pattern,C++,Templates,Design Patterns,Template Method Pattern,注意:以下问题是关于和C++函数模板的。为了区分两者,在引用设计模式时,我会使用斜体字,在引用C++模板时,使用“强> Bruts。 模板方法模式的思想是使算法的某些部分可交换。这通常通过继承实现,子类提供插入基类算法的具体实现。但是,如果钩子方法需要是模板,这将不起作用,因为模板不能是虚拟的。下面是一个不编译的简单示例: class Base { public: // This is the template method template <typename T>

注意:以下问题是关于和C++函数模板的。为了区分两者,在引用设计模式时,我会使用斜体字,在引用C++模板时,使用“强> Bruts。 模板方法模式的思想是使算法的某些部分可交换。这通常通过继承实现,子类提供插入基类算法的具体实现。但是,如果钩子方法需要是模板,这将不起作用,因为模板不能是虚拟的。下面是一个不编译的简单示例:

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);
}
类基
{
公众:
//这是模板方法
模板
无效剂量测定(T输入)
{
//...
自动转换=转换输入(输入);
//...

std::cout听起来像是一个很好的用例。将
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;
    }
};

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

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

如果是有限集,则键入erase所有派生的虚方法。如果是common属性,则键入erase该属性并虚拟化作用于该属性的方法。或者键入一个混合


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

。使
Base
派生的
作为模板参数。通过
static\u cast调用
ConvertInput
(此)->ConvertInput
对用于
T
的类型集是否有任何限制?@Yakk是的,但仅限于隐式类型。例如,其中一个实例需要使用迭代器,迭代器可以是任何类型。@nico迭代可以删除类型。;)谢谢。我已经考虑过这个方向,这肯定是一个可能的解决方案。我也很感兴趣d在不需要将
Base
作为类模板的解决方案中。CRTP的+1:没有读过这一点。如果文章的其余部分让您感到困惑,请仔细阅读有关CRTP的内容,您的问题正适合它。
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);