模板類成員函式特化寫法
阿新 • • 發佈:2019-02-13
通過將關鍵字typename引入到C++中,我們可以對模板定義進行分析。為了分析模板定義,編譯器必須能夠區分出是型別以及不是型別的表示式。如(Parm代表一個類):
template <class Parm,class U>
Parm minus(Parm* array,U value)
{
Parm::name * P; // 這是一個指標宣告還是乘法?答案是乘法
}
編譯器不知道name是否為一個型別,因為它只有在模板被例項化之後才能找到Parm表示的類的定義。為了讓編譯器能夠分析模板定義,使用者必須指示編譯器哪些表示式是型別表示式。告訴編譯器一個表示式是型別表示式的機制是在表示式前加上關鍵字typename。如:
template <class Parm,class U>
Parm minus(Parm* array,U value)
{
typename Parm::name * P; // 這是指標宣告
}
顯式模板實參:
template <class T>
T min5( T, T ) {/* . . . */ }
// min5( unsigned int, unsigned int ) 被例項化
min5< unsigned int >( ui, 1024 );
顯式模板實參應該只被用在完全需要它們來解決二義性,或在模板實參不能被推演出來的上下文中使用模板例項時。大部分情況依賴自動解析。
模板編譯模式
一、包含編譯模式
在包含編譯模式下,我們在每個模板被例項化的檔案中包含函式模板的定義,並且往往把定義放在標頭檔案中,象行內函數所做的那樣。如:
// model1.h
// 包含模式:模板定義放在標頭檔案中
template <typename Type>
Type min( Type t1, Type t2 ) {
return t1 < t2 ? t1 : t2;
}
在每個使用min()例項的檔案中都包含了該標頭檔案,如:
// 在使用模板例項之前包含模板定義
#include "model1.h"
int i, j;
double dobj = min( i, j );
該標頭檔案可以被包含在許多程式文字檔案中。這意味著編譯器必須在每個呼叫該例項的檔案中例項化min()的整型例項嗎?不。該程式必須表現得好像min()的整型例項只被例項化一次。但是,真正的例項化動作發生在何時何地,要取決於具體的編譯器實現。
二、分離編譯模式
在分離編譯模式下,函式模板的宣告被放在標頭檔案中。在這種模式下,函式模板宣告和定義的組織方式與程式中的非行內函數的宣告和定義組織方式相同。如:
// model2.h
// 分離模式:只提供模板宣告
template <typename Type> Type min( Type t1, Type t2 );
// model2.c
// 模板定義
export template <typename Type>
Type min( Type t1, Type t2 ) {/* . . . */}
使用函式模板min()例項的程式只需在使用該例項之前包含這個標頭檔案:
// user.c
#include "model2.h"
int i, j;
double d = min( i, j ); // OK: 用法,需要一個例項
我們通過在模板定義中的關鍵字template之前加上關鍵字export ,來宣告一個可匯出的函式模板。(在CPP檔案中定義模板函式體的方法)
三、顯式例項化宣告
標準C++提供了顯式例項化宣告來幫助程式設計師控制模板例項化發生的時間。在顯式例項化宣告中,關鍵字template後面是函式模板例項的宣告,其中顯式地指定了模板實參。下例中提供了sum(int* , int)的顯式例項化宣告:
template <typename Type>
Type sum( Type op1, int op2 ) {/* . . . */} // 函式模板sum的定義必須給出
// 顯式例項化宣告
template int* sum< int* >( int*, int );
該顯式例項化宣告要求用模板實參int*例項化模板sum()。對於給定的函式模板例項,顯式例項化宣告在一個程式中只能出現一次。
模板函式的例項化會選擇最特化的(most specialized)模板函式,如
template <typename Type>
Type sum( Type*, int );
template <typename Type>
Type sum( Type, int );
int ia[1024];
// Type==int; sum<int>( int*, int ); or
// Type==int*; sum<int*>( int*, int); ??
int ival1 = sum<int>( ia, 1024 );
最特化的是type*版本
template <class Parm,class U>
Parm minus(Parm* array,U value)
{
Parm::name * P; // 這是一個指標宣告還是乘法?答案是乘法
}
編譯器不知道name是否為一個型別,因為它只有在模板被例項化之後才能找到Parm表示的類的定義。為了讓編譯器能夠分析模板定義,使用者必須指示編譯器哪些表示式是型別表示式。告訴編譯器一個表示式是型別表示式的機制是在表示式前加上關鍵字typename。如:
template <class Parm,class U>
Parm minus(Parm* array,U value)
{
typename Parm::name * P; // 這是指標宣告
}
顯式模板實參:
template <class T>
T min5( T, T ) {/* . . . */ }
// min5( unsigned int, unsigned int ) 被例項化
min5< unsigned int >( ui, 1024 );
顯式模板實參應該只被用在完全需要它們來解決二義性,或在模板實參不能被推演出來的上下文中使用模板例項時。大部分情況依賴自動解析。
模板編譯模式
一、包含編譯模式
在包含編譯模式下,我們在每個模板被例項化的檔案中包含函式模板的定義,並且往往把定義放在標頭檔案中,象行內函數所做的那樣。如:
// model1.h
// 包含模式:模板定義放在標頭檔案中
template <typename Type>
Type min( Type t1, Type t2 ) {
return t1 < t2 ? t1 : t2;
}
在每個使用min()例項的檔案中都包含了該標頭檔案,如:
// 在使用模板例項之前包含模板定義
#include "model1.h"
int i, j;
double dobj = min( i, j );
該標頭檔案可以被包含在許多程式文字檔案中。這意味著編譯器必須在每個呼叫該例項的檔案中例項化min()的整型例項嗎?不。該程式必須表現得好像min()的整型例項只被例項化一次。但是,真正的例項化動作發生在何時何地,要取決於具體的編譯器實現。
二、分離編譯模式
在分離編譯模式下,函式模板的宣告被放在標頭檔案中。在這種模式下,函式模板宣告和定義的組織方式與程式中的非行內函數的宣告和定義組織方式相同。如:
// model2.h
// 分離模式:只提供模板宣告
template <typename Type> Type min( Type t1, Type t2 );
// model2.c
// 模板定義
export template <typename Type>
Type min( Type t1, Type t2 ) {/* . . . */}
使用函式模板min()例項的程式只需在使用該例項之前包含這個標頭檔案:
// user.c
#include "model2.h"
int i, j;
double d = min( i, j ); // OK: 用法,需要一個例項
我們通過在模板定義中的關鍵字template之前加上關鍵字export
三、顯式例項化宣告
標準C++提供了顯式例項化宣告來幫助程式設計師控制模板例項化發生的時間。在顯式例項化宣告中,關鍵字template後面是函式模板例項的宣告,其中顯式地指定了模板實參。下例中提供了sum(int* , int)的顯式例項化宣告:
template <typename Type>
Type sum( Type op1, int op2 ) {/* . . . */} // 函式模板sum的定義必須給出
// 顯式例項化宣告
template int* sum< int* >( int*, int );
該顯式例項化宣告要求用模板實參int*例項化模板sum()。對於給定的函式模板例項,顯式例項化宣告在一個程式中只能出現一次。
模板函式的例項化會選擇最特化的(most specialized)模板函式,如
template <typename Type>
Type sum( Type*, int );
template <typename Type>
Type sum( Type, int );
int ia[1024];
// Type==int; sum<int>( int*, int ); or
// Type==int*; sum<int*>( int*, int); ??
int ival1 = sum<int>( ia, 1024 );
最特化的是type*版本