实现模板化模板方法
Implementing templated template method
注:以下问题是关于Template Method Design Pattern和C++函数模板的。为了区分两者,我将在提及设计模式时使用 斜体,在提及 C++ 模板时使用 粗体。
模板方法模式的思想是让算法的各个部分可以互换。这通常是通过继承来实现的,其中 subclass 提供了插入基础 class 算法的具体实现。但是,如果钩子方法需要是 templates,这将不起作用,因为 templates 不能是虚拟的。这是一个无法编译的简单示例:
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
class 作为类型不感兴趣。我将始终使用具体的特定类型来实现最大的编译时优化。所以这个问题的另一种表述是:我如何创建多个 classes Derived-1 .. Derived-n
具有 函数模板 在实现中共享一个公共代码框架?
听起来像是 CRTP 的一个很好的用例。将 Base
定义为 class 模板,并将派生的类型作为模板参数。在 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
注:以下问题是关于Template Method Design Pattern和C++函数模板的。为了区分两者,我将在提及设计模式时使用 斜体,在提及 C++ 模板时使用 粗体。
模板方法模式的思想是让算法的各个部分可以互换。这通常是通过继承来实现的,其中 subclass 提供了插入基础 class 算法的具体实现。但是,如果钩子方法需要是 templates,这将不起作用,因为 templates 不能是虚拟的。这是一个无法编译的简单示例:
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
class 作为类型不感兴趣。我将始终使用具体的特定类型来实现最大的编译时优化。所以这个问题的另一种表述是:我如何创建多个 classes Derived-1 .. Derived-n
具有 函数模板 在实现中共享一个公共代码框架?
听起来像是 CRTP 的一个很好的用例。将 Base
定义为 class 模板,并将派生的类型作为模板参数。在 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