今天在书店里翻 "C++ template" 学习了一下以前一直不明白的Metaprogramming,发现原来就是那个在模板里加enum的技巧的应用,仔细想一下果然可以衍生出很多用途,下面是一个最简单的例子:
#include <iostream>
using namespace std;
template<int n>
class twoPower
{
public:
enum { result = 2*twoPower<n-1>::result };
};
template<>
class twoPower<0>
{
public:
enum {result = 1};
};
int main()
{
cout << twoPower<5>::result <<endl;
}
定义了一个用来算2的n次方的模板,用了模板的特化来做为递归的终止条件。第一次接触到这样形式的模板应用是在"Modern C++ Design" 的typelist里,当时就非常的惊讶,发现C++的表达能力实在是我无法想像的。
今天,书店里思考了一会儿,觉得这个技术可以用来在编译期实现类似.net中attribute的东西。回来在机器上试了一下,像这样:
首先定义一个attribute的模板类,并提供一个默认值:
template<typename T>
class SerializableAttribute
{
public:
enum { IsSerializable = 0 };
};
然后你定义了一个自己的类,比如这样:
class myClass
{
};
为了应用上面的那个Attribute,你需要为你的类提供一个特化:
template<>
class SerializableAttribute<myClass>
{
public:
enum {IsSerializable = 1 };
};
然后,在其它地方就可能用到这个attribute。(reflect吗? )
int main()
{
if (SerializableAttribute<myClass>::IsSerializable) cout << "myClass can be serialized." <<endl;
else cout <<"myClass can't be serialized" <<endl;
}
我想以上这种应用,应该就是这种技术被称为metaprogramming的原因吧。这样的Attribute和.net中的Attribute最大的大区别是它是静态的,因为模板的推导工作全部都是在编译期完成的,而不是像.net中那样将metadata编译进assembly里,然后再在执行期运用反射来获取。这当然会使得它的用途受到诸多限制。
不过有时候我在想,像C++这样缺乏运行时支持,到底是劣势呢?还是优势呢? 最近在研究C#2.0中的泛型机制,其中新提出来的 约束 的机制,我个人猜测很可能就是因为C#太强大的反射机制,导致泛型的推导,不能像C++那样完全在编译期完成,才不得不加上的。
C++中的编译期多态,在C#中似乎也没有办法使用了。不过说不定加入泛型的C#,又会生出许多新的应用,谁知道呢! 当初为C++加入模板的时候,stroustup教授自己恐怕也没有想到泛型会有今天的发展吧。语言总会给我们带来惊喜,谁说不是呢。