C++ 实现模板化模板方法
注意:以下问题是关于和C++函数模板的。为了区分两者,在引用设计模式时,我会使用斜体字,在引用C++模板时,使用“强> Bruts。 模板方法模式的思想是使算法的某些部分可交换。这通常通过继承实现,子类提供插入基类算法的具体实现。但是,如果钩子方法需要是模板,这将不起作用,因为模板不能是虚拟的。下面是一个不编译的简单示例: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>
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该属性并虚拟化作用于该属性的方法。或者键入一个混合
否则,基可以具有将操作作为函数对象(使用templateoperator()
)的模板方法,而不是使用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);