#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;}这就是编译优化之后的伪代码,执行的顺序在优化后完全确定,优化后的代码往往简单,高效。

评论