"奇特重复发生的模板模式"的实际用途
"好奇地重复使用的模板模式"有哪些实际用途?通常显示的"计数类"示例对我来说不是一个令人信服的示例。
解决方案
模拟动态绑定。
对于子系统来说,避免虚拟函数调用的成本,同时保留一些分层的好处是一个巨大的胜利,因为子系统可以在我目前正在研究的项目中完成。
通常,它用于类似多态的模式,在这些模式中,我们不必仅在编译时就可以在运行时选择派生类。这样可以节省运行时虚拟函数调用的开销。
感觉有点像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的定义推迟到实例化模板之前。除非在这种情况下,这是基于Parent中T的值来区分ClassA :: foo和ClassB :: foo。
这对于混入(我是指我们从其继承的类以提供功能)特别有用,混入本身需要知道其操作的类型(因此需要是模板)。
在Effective C ++中,Scott Meyers提供了一个类模板NewHandlerSupport <T>作为示例。它包含一个静态方法来覆盖特定类的新处理程序(以与std :: set_new_handler对默认运算符new相同的方式),以及一个使用该处理程序的new运算符。为了提供每个类型的处理程序,父类需要知道其作用于哪种类型,因此它必须是一个类模板。 template参数是子类。
如果没有CRTP,我们将无法真正做到这一点,因为我们需要分别实例化NewHandlerSupport模板,并使用一个单独的静态数据成员来存储使用它的每个类的当前new_handler。
显然,整个示例是极其非线程安全的,但它说明了这一点。
Meyers建议将CRTP视为"为我做"。我会说,通常对于任何mixin都是这种情况,CRTP适用于需要mixin模板而不是仅仅需要mixin类的情况。
如果我们认为仅在方法扩展时才需要传递给超类的子类类型,那么CRTP就会变得不那么好奇了。
这样就定义了所有类型。
我们只需要将符号子类类型导入超类的模式,但这只是一个前向声明,因为就超类而言,所有形式化的模板参数类型都是按定义定义的。
我们使用经过某种修改的形式,将traits类型结构中的子类传递给超类,以使超类有可能返回派生类型的对象。该应用程序是一个用于几何演算(点,向量,线,框)的库,其中所有通用功能都在超类中实现,而子类仅定义特定类型:CFltPoint继承自TGenPoint。 CFltPoint也在TGenPoint之前存在,因此子类化是重构它的自然方法。
对于CRTP的真实库使用,请查看ATL和WTL(wtl.sf.net)。那里广泛用于编译时多态性。