“Curiously Recurring Template Pattern”的一些实际用途是什么?通常显示的“counted class”示例对我来说并不是一个令人信服的例子。
答案 0 :(得分:20)
Simulated dynamic binding。 避免虚拟函数调用的成本同时保留一些分层优势是子系统的巨大胜利,它可以在我目前正在进行的项目中完成。
答案 1 :(得分:20)
它对于 mixins (我指的是你继承的类来提供功能)也特别有用,它们本身需要知道它们在什么类型上运行(因此需要是模板)。 / p>
在 Effective C ++ 中,Scott Meyers提供了一个类模板NewHandlerSupport< T>作为示例。这包含一个静态方法来覆盖特定类的新处理程序(与std :: set_new_handler对默认运算符new的处理方式相同),以及使用处理程序的operator new。为了提供每类型处理程序,父类需要知道它所处理的类型,因此它需要是一个类模板。 template参数是子类。
如果没有CRTP,你真的不能这样做,因为你需要单独实例化NewHandlerSupport模板,并使用一个单独的静态数据成员来存储当前的new_handler,每个使用它的类。
显然整个示例都是非线程安全的,但它说明了这一点。
迈尔斯建议CRTP可能会被认为是“为我而做”。我会说任何mixin都是这种情况,CRTP适用于需要mixin模板而不仅仅是mixin类的情况。答案 2 :(得分:4)
如果您认为仅在方法扩展时需要传递给超类的子类类型,那么CRTP就不那么好奇了。 那么就定义了所有类型。 你只需要模式将符号子类类型导入到超类中,但它只是一个前向声明 - 因为所有正式模板参数类型都是定义的 - 就超类而言。
我们使用一种稍微修改过的形式,将traits类型结构中的子类传递给超类,以使超类能够返回派生类型的对象。该应用程序是一个用于几何微积分(点,向量,线,框)的库,其中所有通用功能都在超类中实现,子类只定义一个特定类型:CFltPoint继承自TGenPoint。此外,CFltPoint在TGenPoint之前就已存在,因此子类化是重构这一点的一种自然方式。
答案 3 :(得分:1)
通常,它用于类似多态的模式,您不需要在运行时选择派生类,只能在编译时。这可以节省运行时虚函数调用的开销。
答案 4 :(得分:1)
对于CRTP的真实图书馆使用,请查看ATL和WTL(wtl.sf.net)。它广泛用于编译时多态性。
答案 5 :(得分:-1)
感觉有点像C宏:利用宏不是在定义时编译,而是在使用时编译。
#define CALL_THE_RIGHT_FOO foo()
文件A:
static void foo() {
// do file A thing
}
...
CALL_THE_RIGHT_FOO
...
文件A:
static void foo() {
// do file B thing
}
...
CALL_THE_RIGHT_FOO
...
您正在描述的模板使用模式允许我们在父模板中“调用正确的foo”,推迟确定正确的foo是什么,直到模板被实例化。除了在这种情况下,它是ClassA :: foo和ClassB :: foo之间的区别,基于Parent中的T值。