C++的模板(四):编译问题

现在,换一种方式来看hanoi塔问题。这次用模板。来看这段代码:

#include <iostream>
using namespace std;

template <int n, int a, int b, int c>
class Tower {
    
    
public:
        Tower() {
    
    
        Tower<n-1, a, c, b> t1;
        cout<<"move plate"<<n<<" from "<<"ABC"[a]<<" to "<<"ABC"[c]<<"\n";
        Tower<n-1, b, a, c> t2;
        }
};

template <int a, int b, int c>
class Tower<1,a,b,c> {
    
    
public:
        Tower() {
    
    
        cout<<"move plate"<<1<<" from "<<"ABC"[a]<<" to "<<"ABC"[c]<<"\n";
        }
};


int main()
{
    
    
        Tower<10, 0, 1, 2> hanoi;
}

代码是超级简单的。大于一层的hanoi塔含有两个子hanoi塔问题,它们的类型分别是Tower<n-1, a, c, b>和Tower<n-1, b, a, c>。移动盘子的操作是在构造函数里完成的。所以,定义一个hanoi变量就好了,什么都不用做。

这段代码编译时会给编译器带来什么样的开销呢?因为每个Tower实例,都用到了两个n-1层的子类型,咋一看一共生成2的n次方-1个类型。然而,根据完全2-叉树的推算公式每一层有2的i次方个节点。而每一层,按a,b,c的全排列,最多只能生成6个类型,所以没那么多。数学推导就不做了,仍然利用这个代码自动计算数一下。

#include <iostream>
using namespace std;


#define MAX 10
int count[MAX][6];

enum {
    
    I_abc, I_acb, I_bac, I_bca, I_cab, I_cba};
#define TEST_VAL(a,b,c)   (a<<8|b<<4|c)

int add(int n, int a, int b, int c)
{
    
    
        extern int count[MAX][6];
        switch(TEST_VAL(a,b,c)) {
    
    
        case TEST_VAL(0,1,2):
                        if(count[n-1][I_abc]) return 0;
                        count[n-1][I_abc]=1;
                        break;
        case TEST_VAL(0,2,1):
                        if(count[n-1][I_acb]) return 0;
                        count[n-1][I_acb]=1;
                        break;
        case TEST_VAL(1,0,2):
                        if(count[n-1][I_bac]) return 0;
                        count[n-1][I_bac]=1;
                        break;
        case TEST_VAL(1,2, 0):
                        if(count[n-1][I_bca]) return 0;
                        count[n-1][I_bca]=1;
                        break;
        case TEST_VAL(2, 0,1):
                        if(count[n-1][I_cab]) return 0;
                        count[n-1][I_cab]=1;
                        break;
        case TEST_VAL(2,1,0):
                        if(count[n-1][I_cba]) return 0;
                        count[n-1][I_cba]=1;
                        break;
        }
        return 1;
}


template <int n, int a, int b, int c>
class Tower {
    
    
public:
        Tower() {
    
    
        if (!add(n,a, b,c)) return;
        Tower<n-1, a, c, b> t1;
        cout<<"move plate"<<n<<" from "<<"ABC"[a]<<" to "<<"ABC"[c]<<"\n";
        Tower<n-1, b, a, c> t2;
        }
};

template <int a, int b, int c>
class Tower<1,a,b,c> {
    
    
public:
        Tower() {
    
    
        if (!add(1,a, b,c)) return;
        cout<<"move plate"<<1<<" from "<<"ABC"[a]<<" to "<<"ABC"[c]<<"\n";
        }
};


int main()
{
    
    
        extern int count[MAX][6];
        Tower<10, 0, 1, 2> hanoi;
        int i, j;
        for(i=0; i<10; i++) {
    
    
                cout <<i+1<<":";
                for(j=0; j<6; j++)  {
    
    
                        cout <<"  ";
                        if (count[i][j]) {
    
    
                                cout<< "x";
                        }
                        else cout << ".";
                }
                cout <<"\n";
        }

}

这里count数组意外的和std名称空间的某个东西冲突了。只好在函数体里再用extern说明一下。看来using namespace std;这句话有点大了…

这是运行结果:

move plate ...
move ...

1:  .  x  x  .  .  x
2:  x  .  .  x  x  .
3:  .  x  x  .  .  x
4:  x  .  .  x  x  .
5:  .  x  x  .  .  x
6:  x  .  .  x  x  .
7:  .  x  x  .  .  x
8:  x  .  .  x  x  .
9:  .  x  x  .  .  .
10:  x  .  .  .  .  .

可见除了最后两层,每层都生成3个类型。总共是 3 *(n-2) +3 = 3 *n -3
编译器总共实例化生成 3 *n -3个Tower类型。

Guess you like

Origin blog.csdn.net/aaasssdddd96/article/details/108278351