C++模板:名称查找

2015-01-27 06:11:59 · 作者: · 浏览: 8

在编译模板的时候,编译器会分两个阶段去解析遇到的名称,第一个阶段解析不依赖于模板参数的名称,第二个阶段解析依赖于模板参数的名称,下面举个简单的例子来说明这一点:

template
  
    class X {
public:
	typedef int E;
};

typedef double E;

template
   
     class Y : public X
    
      { public: E f() {} };
    
   
  
这个例子中定义了两个类模板,其中Y派生于X,在X中我们给int取了个别名E,接着在全局作用域中给double也取了个别名E,在Y中有一个函数f(),它的返回值类型为E,那么这个E到底是double呢,还是int?结果是double,因为f()不依赖与模板参数T,所以它在第一阶段就会被解析,而它的基类X<.T>在第二阶段才会被解析,所以解析f()的时候只能看到全局作用域里的typedef double E。如果大家心里有疑问,我们可以看看非模板类的情况:

class X {
public:
	typedef int E;
};

typedef double E;

class Y : public X {
public:
	E f() {}
};

int main(){

	Y y;
	cout<
  
   这个例子中都是普通的类,通过main函数的测试,可以看到f()的返回类型变成了int。接下来我们再来看一个例子:
   

void g() { cout<<"gobal::g()"<
    
      class X {
public:
	typedef int E;
	void g() { cout<<"X::g()"<
     
       class Y : public X
      
        { public: E f() { g(); this->g(); } }; int main(){ Y
       
         y; cout<
        
         这个例子中首先定义了一个全局函数g(),接着定义了类模板X,在X中定义了一个成员函数g(),类模板Y依然继承于X,在Y中的f()中“以两种方式”调用了g(),那么这两种方式调用的是同一个g()吗?答案是:不是,第一种方式调用了全局的g(),而第二种方式调用了基类的g(),原因在于当编译器遇到第一种方式的g()时,发现它没有表现出要依赖于模板参数,所以认为它不依赖于模板参数,因而在第一阶段就进行了解析,此时X
         
          尚未解析,所以g()是全局的g(),通过第二种方式调用时,用this指针指出g()是依赖于当前对象的,也就依赖于模板参数,因而会在第二阶段解析,那时基类也会先于Y进行了解析,所以this-->g()调用了基类的g()。同样,我们可以看看普通类的情况:
          

void g() { cout<<"gobal::g()"<
           
             class X {
public:
	typedef int E;
	void g() { cout<<"X::g()"<
            
              class Y : public X
             
               { public: E f() { g(); this->g(); } }; int main(){ Y
              
                y; cout<
               
                结果会发现,两次都调用了基类X的g(),这个例子告诉我们,在类模板中,如果需要使用成员函数,需要通过this指针来指定,而不能像在普通类中那样省略到this指针,事实上,如果不用this指针来指定,而又没有全局函数g(),编译时会出现如下错误:
                
error:there are no arguments to 'g' that depend on a template parameter, so a declaration of 'g' must be available.