GNU C++ (MinGW Special)的下载、使用以及模板元编程…… 我在编写C++程序和测试C++特性时,最常使用GNU C++ (MinGW Special)(以下简称G++)、BCB5、VC7和Digital Mars四种编译器。我的经验是,在面向对象领域,这几种编译器对标准的实现难分高下,但在模板尤其是高级模板特性领域,G++ 3.2表现最为出色(当然也谈不上完美)。
G++是GCC中的一员。GCC的含义是GNU编译器集合(GNU Compiler Collection),包括C、C++、Objective-C、Fortran、Java、Ada连同与这些语言相配的库等。GCC被誉为 “世界上最重要的软件”。许多免费的编译器都是GCC的移植版 — MinGW(Minimalist GNU for Windows)中携带的编译器就是如此。在写这篇文章时(2003/9/23),GCC的最新版本是3.3.1,而最新版的MinGW 3.1.0支持的GCC版本是3.2.3。(注:如欲了解GCC和MinGW正式完整的描述,请访问http://gcc.gnu.org和http://sourceforge.net/projects/mingw) http://sourceforge.net/projects/mingw提供了详细的文件下载列表。如果你暂时无法确定该下载哪些文件,下载MinGW-3.1.0-1.exe即可(其它文件待你弄明白后视需要下载)。这个文件大小为14.5 MB,除了包含有一组C/C++编译器外,还带有一个用于编译FORTRAN 77的g77编译器以及其他一些辅助工具和文件。下载后直接安装即可,无需任何额外的配置。当然,你也可以为编译器设置一个PATH环境变量(例如c:\mingw\bin;)。这种一劳永逸之举多少可为自己日后省点麻烦。 我们的兴趣在于G++。它的用法非常简单: g++ -o dftest.exe dftest.cpp delimfile.cpp 键入g++ --help命令即可查看完整编译和连接选项。 在1994年C++标准委员会的一次会议期间,Erwin Unruh展示了一个可以产生质数的程序。此程序特别之处在于质数的产生发生于编译期而非运行期。在编译器产生的一系列错误信息中间夹杂着从2到某个设定值之间的所有质数。它展示了可以利用模板实例化机制于编译期执行一些计算。这种通过模板实例化而执行的编译期计算技术,即是广为人知的模板元编程(Template Metaprogramming)。 当年Erwin Unruh凭借Metaware编译器展示了这一有趣的效果,幸运的是,今天触手可及的G++还能为我们完整再现之。也怪不得其他几款编译器,因为编译器的出错信息并未被标准化。 下面就是94年那次会议期间广为流传的代码之修订版(为了能够在今天符合标准的编译器上进行编译,做了少许修改): // Prime number computation by Erwin Unruh
template <int i> struct D { D(void*); operator int(); };
template <int p, int i> struct is_prime { enum { prim = (p==2) || (p%i) && is_prime<(i>2?p:0), i-1> :: prim }; };
template <int i> struct Prime_print { Prime_print<i-1> a; enum { prim = is_prime<i, i-1>::prim }; void f() { D<i> d = prim ? 1 : 0; a.f();} };
template<> struct is_prime<0,0> { enum {prim=1}; }; template<> struct is_prime<0,1> { enum {prim=1}; };
template<> struct Prime_print<1> { enum {prim=0}; void f() { D<1> d = prim ? 1 : 0; }; };
#ifndef LAST #define LAST 18 #endif
main() { Prime_print<LAST> a; a.f(); } 因为类模板D只有一个参数为void*的构造器,而只有0才能被合法转换为void*,因此,在g++上编译这段程序时,编译器将会给出如下错误信息(以及其他一些信息。简短起见,它们被删除了): unruh.cpp:12: invalid conversion from `int' to `void*' unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 17]' unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 13]': unruh.cpp:12: invalid conversion from `int' to `void*' unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 13]' unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 11]': unruh.cpp:12: invalid conversion from `int' to `void*' unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 11]' unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 7]': unruh.cpp:12: invalid conversion from `int' to `void*' unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 7]' unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 5]': unruh.cpp:12: invalid conversion from `int' to `void*' unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 5]' unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 3]': unruh.cpp:12: invalid conversion from `int' to `void*' unruh.cpp:12: initializing argument 1 of `D<i>::D(void*) [with int i = 3]' unruh.cpp: In member function `void Prime_print<i>::f() [with int i = 2]': C++模板元编程技术在Blitz++[http://www.oonumerics.org/blitz/]这样的数值矩阵库中得到了进一步的应用。如果你对编译期计算和模板元编程技术感兴趣,我推荐你阅读《C++ Templates: The Complete Guide》一书。幸运的是,内地和台湾年内都将出版这部著作的中文版。 荣耀 2003年9月 南京师范大学 www.royaloo.com |