正文

模板的妙用2006-08-01 20:59:00

【评论】 【打印】 【字体: 】 本文链接:http://blog.pfan.cn/sonicling/17096.html

分享到:

#include <cstdlib>#include <iostream>using namespace std;template<typename T, size_t n>bool __is_array(T (&a)[n]) {return true;}bool __is_array(...) {return false;}template<typename T>bool IsArray(T &a){    return __is_array(a);}template<typename T, size_t n>void Test( T (&array)[n], bool first = false);template<typename T, size_t n>void Test_Shadow( T (&array)[n]);template<typename T>void Test( T& ){}template<typename T>void Test_Shadow( T& ){}template<typename T, size_t n>void Test( T (&array)[n], bool first ){    if(first) cout << "the array is like A";    cout << "[" << n << "]";    if(IsArray(array[0]))        Test_Shadow(array[0]);    else cout << endl;}template<typename T, size_t n>void Test_Shadow( T (&array)[n]){    cout << "[" << n << "]";    if(IsArray(array[0]))        Test(array[0]);    else cout << endl;}int main(){  char test[2];  char test2[2][3];  char test3[2][3][4];  Test(test, true);  Test(test2, true);  Test(test3, true);  system("pause");  return 0;}the array is like A[2]the array is like A[2][3]the array is like A[2][3][4]请按任意键继续. . . 分析: 首先看下面这段template<typename T, size_t n>bool __is_array(T (&a)[n]) {return true;}bool __is_array(...) {return false;}template<typename T>bool IsArray(T &a){    return __is_array(a);}如果IsArray的参数a是数组的话,编译器一定会选择template<typename T> bool __is_array(T (&a)[n]),因为不定参数的bool __is_array(...)永远是最后才考虑的选项。由此IsArray就可以判断参数是否为数组。再来看接下来的template<typename T, size_t n>void Test( T (&array)[n], bool first = false);template<typename T, size_t n>void Test_Shadow( T (&array)[n]);这是两个函数的声明,由于这两个函数相互嵌套第归,因此必须先声明再定义,从后面的定义来看,这两个函数几乎是一模一样的,按道理完全可以归为一个,但是实际上是不行的。如果我像下面这样定义Test函数形成单一函数的递归template<typename T, size_t n>void Test( T (&array)[n], bool first ){    if(first) cout << "the array is like A";    cout << "[" << n << "]";    if(IsArray(array[0]))        Test(array[0]); // 单独递归    else cout << endl;}那么在编译的时候会有问题,array是T (&)[n]类型,那么array[0]就是T 类型,而不管T是否是数组,这个Test<T>本身都不会接受T类型作为第一个参数,编译会出错。而使用双函数相互递归,编译器就会重新分析T的实际类型。再来看接下来的两个重载:template<typename T>void Test( T& ){}template<typename T>void Test_Shadow( T& ){}实际上什么都不做。不管IsArray返回true或者false,编译器都必须处理Test( T& )的调用,也就是说必须要让Test接受非数组作为参数。因此有了这两个重载。最后看看实际的效果:编译器处理IsArray的时候,由于两个__is_array都可以内联,因此IsArray只有下面两个版本:bool IsArray<T (&)[n]>(T (&)[n]){   return true;}bool IsArray<T, n>(T &){   return false;}显然这两个实例化的IsArray同样也可以内联的,因此Test函数里面的if(IsArray())调用最后被内联为if(true)或者if(false)。对于Test<T (&)[][n], n>(T (&)[n], bool)来说一定对应于if(true),而对于Test<T (&)[n], n>(T (&)[n], bool)来说,一定对应于if(false),进一步优化实际上对if语句可以进行分支筛选,把不可能执行的部分筛选掉。由于Test和Test_Shadow是相互嵌套递归,每次递归调用都会重新分析T类型从而产生新的Test和Test_Shadow实例,而这些实例在优化条件下都可以被内联,因而整个程序的执行顺序和路径在编译优化之后就已经确定下来。例如对于Test(test2, true);这一条语句编译优化之后产生的Test实例可能是这样的:void Test<char (&)[2][3], 2>(char (&array)[2][3], bool first){    if(first) cout << "the array is like A";    cout << "[" << 2 << "]";    // if(IsArray(array[0])) => if(true) => 省略        // Test_Shadow(array[0]);被内联展开为        // Test_Shadow<char (&)[3], 3>(char (&array)[3])        // {                cout << "[" << 3 << "]";                // if(IsArray(array[0])) => if(false) => 省略                    // Test(array[0]); => 该分支直接省略                // else => 该分支直接展开为                cout << endl;        // }    // else cout << endl; => 该分支直接省略}把注释去掉,即为如下:void Test<char (&)[2][3], 2>(char (&array)[2][3], bool first){    if(first) cout << "the array is like A";    cout << "[" << 2 << "]";    cout << "[" << 3 << "]";    cout << endl;}这就是编译优化之后的伪代码,执行的顺序在优化后完全确定,优化后的代码往往简单,高效。

阅读(3013) | 评论(0)


版权声明:编程爱好者网站为此博客服务提供商,如本文牵涉到版权问题,编程爱好者网站不承担相关责任,如有版权问题请直接与本文作者联系解决。谢谢!

评论

暂无评论
您需要登录后才能评论,请 登录 或者 注册