模板函数定义中的名字解释和模板函数的实例化点

来源:互联网 发布:善领gt318升级软件 编辑:程序博客网 时间:2024/06/10 08:45

  在模板定义中有些结构在两个模板实例之间有不同的意思,而另外一些结构在模板的所有实例之间意想同。这取决于该结构是否涉及到模板的参数。如以下模板的定义:

template< typename T >
T min( T* array, int size )
{
 T min_val = array[0];
 for( int i=1; i<size; ++i )
 {
  if( array[i] < min_val )
   min_val = array[i];
 }

 print( "Minimum value found: " );
 print( min_val );

 return min_val;
}

在min()中,array和min_val的类型取决于模板被实例化时取代T的实际类型,随不同的模板实例而不同。因此,我们说这些变量的类型依赖于模板参数(depend on a template parameter)。

  我们知道,函数必须在调用前被声明。那么在模板定义中,被调用的函数必须在模板定义出现之前被声明吗?这取决于我们引用了哪种名字的函数:不依赖于模板参数的结构必须使用之前先声明、依赖于模板参数的结构必须在实例化之前声明。因此,print( "Minimum value found: " )这个对应的函数原形就必须在模板定义之前声明,而print( min_val )这个对应的函数原形就必须在模板被实例化之前声明。

  所以,模板定义中的名字解析分两个步进行。首先,不依赖于模板参数的名字在模板定义时被解析;其次,依赖于模板参数的名字在模板被实例化时被解析。你可能会问,为什么要分两步呢?为什么还是所有的名字都在模板被实例化时被解析呢?软件工程中有句话叫做:“问题越早发现,就越容易解决,花费就越少”。

  在源代码中模板被实例化的位置被称为实例化点(point of instantiation)。知道模板的实例化点是很重要的,因为它决定了对依赖于模板参数的名字所考虑的声明。函数模板的实例化点总是跟在调用模板函数的函数的后面。如:

//...
int main()
{
    //...
   
    //使用min( int*, int )
    min( iarray, size );
}
//min( int*, int )的实例化点,定义如下:
int min( int*, int )
{ /*...*/ }

但是,如果在一个源文件中,一个模板实例不只被使用一次,又该怎么确定实例化点在哪儿呢?当模板实例要多次使用时,在每个使用该实例的函数定义之后都有一个实例化点。编译器自由选择这些实例化点中之一来真正实例化该函数模板。这就意味着在组织代码时,我们必须小心地把解析依赖于模板参数的名字所需要的声明放置在模板的所有实例化点之前。如:

//依赖性名字的相关声明
void another();
int main()
  //...
    min( iarray, size );
    another();
}
//min( int*, int )的第一个实例化点
//...
void another()
{   //...
    min( iarray, size );
}
//min( int*, int )的第二个实例化点