一、CRTP的说明
CRTP是一种静态多态的实现方法。说的直白一些就是在正常的认知中,子类继承的是父类,但是如果父类是一个模板类,此模板类中的模板参数是子类的这种特殊情况。CRTP在前面说过两次,如果有对此技术不清楚的可以查看一下“跟我学c++中级篇——CRTP”以及“显式this的应用”中都进行过分析说明。
CRTP本身就是一种很小众的技术应用,而它的一些应用,可能应用范围更小,下面就一些细节进行分析,扩展一下CRTP的更多的应用场景,给大家提供一些应用上的思路。
二、高级应用
CRTP的应用,相对来说就是一种比较复杂的应用。在前面将其基础的一些应用进行了分析说明,本次就CRTP在模板编程中的一些更高级的用法分析一下:
1、模板参数的高级处理
在前面的CRTP文章中基本都是正常的一个参数,其实CRTP模板参数是可以有1~N个或者有默认参数的,看一下代码:
#include <iostream>
#include <string>template <typename T1, typename T2>
class Base {
public:void run(const std::string& d) {if(T2::work()) {static_cast<T1*>(this)->run(d);}}
};struct Condition {static bool work() {std::cout << "condition work" << std::endl;return true;}
};int main() {Derived d;Base<Derived,Condition> *b = &d;b->run("test");//注意和第二种方式调用的不同 return 0;
}
默认参数的处理同样适用于这种情况,大家根据实际情况处理即可,反而更简单。
使用这种多参数的控制,特别是灵活的使用调用方式(参看上下两段代码的注释内容),可以动态的利用具体的场景实现特定的需求。
2、编译及运行优化的支持
最常见的运行优化是使用内联。看下面的例子:
#include <iostream>template <typename T>
class Base {
public:inline int sub(int a, int b) {return static_cast<T*>(this)->subExe(a, b);}
};class Derived : public Base<Derived> {
public:inline int subExe(int a, int b) {return a - b;}
};int main() {Derived d;std::cout << "sub value: " << d.sub(12, 7) << std::endl;//注意和第一种方式调用的不同 return 0;
}
使用内联其实有很多的限定场景,大家一定要能准确的把握内联的限制条件及相关的优缺点,才能更好的使用这种方式。
在模板中是不支持模板的分离编译的,但是CRTP有一个特别的情况,如果假定某个情况下只支持一种子类,那么就可以显示的实例化这个模板,从而减少模板实例化的数量,达到编译期优化的目的。这也算了CRTP的一个特别的应用。不过觉得这种应用稍显有些鸡肋。所以就不举例了,大家可以根据情况自己简单写一个例程测试一下即可。
三、总结
CRTP做为一种模板编程技术,在某些特定的场景下,能够实现一些特殊的技巧,从而提高程序的效率。其实不单单上面的几种情况,CRTP做为一种技术可以与其它的相关的应用广泛结合在一起,目的只有一个,能够让程序的灵活性和适用性更强。
不过,有一个应用的前提,就是尽量减少代码的复杂度。换句话说,不能追求单项目标的极致,而要综合平衡所有的既有条件,整体上达到一个最优。这就需要设计者和开发者能够从宏观把握全局路径,不断进行调整和优化。而上述所讲的这些应用,就是此过程中可以用到的手段和技巧。