2012-01-21 53 views
6
#include <iostream> 
template <class T> 
void foo(T) { 
    std::cout << "foo(T)" << std::endl; 
} 

template <class T> 
void foo(T*) { //#3 
    std::cout << "foo(T*)" << std::endl; 
} 

#define TEST 

#ifdef TEST 
template <> 
void foo(int*) { //#1 
    std::cout << "foo(int*)" << std::endl; 
} 
#else 
template <> 
void foo<int*>(int*) { //#2 
    std::cout << "foo<int*>(int*)" << std::endl; 
} 
#endif 

int main(int argc, char **argv) { 
    int* p = 0; 
    foo(p); 
    return 0; 
} 

#1和#2有什麼區別。如果我定義TEST,#1工作。但是,如果我評論它,#3 工作...哪個是寫功能模板專業化的正確方法...函數模板專精失敗?

回答

3

#1宣稱的#3函數模板專業化和自動推導模板參數。 #2是您爲T=int*定義的第一個模板(沒有數字的那個,我們稱之爲#0)的專業化。它不能是#3的專業化,因爲用指定的int*代替T將導致int**參數。

當您致電foo時,重載解析現在首先選擇最合適的基本模板,然後檢查該模板是否存在任何現有的特化。使用TEST定義,有兩個基本模板(#0和#3)和#3是一個更好的匹配並被選中。然後,編譯器檢查該模板的特化,#1更適合並被調用。

沒有TEST定義,仍然有兩個基本模板(#0和#3)和#3是更好的匹配並被選中。然後編譯器檢查該模板的特化,但是因爲#2專門研究#0而不是#3,所以它不被考慮,並且#3被調用。

這是Why not Specialize Function Templates的經典示例。那裏會更詳細地解釋這些問題。

簡單的解決辦法是在所有不擅長的功能模板,但只是對於特殊類型添加新的重載:

// no template, just a normal function 
void foo(int*) { 
    std::cout << "foo(int*)" << std::endl; 
} 
0

我真的不知道哪個功能#2應該專門化,或者究竟如何極其複雜的重載解析規則會選擇要調用的函數。

我知道你最經常不需要需要專門的功能,但可以依靠重載。爲了得到一個功能int*你只需要

void foo(int*) { 
    std::cout << "foo(int*)" << std::endl; 
} 

非模板函數會被優先於模板,只要參數相匹配。

+0

有一些情境它是方便或需要指定模板參數(S) 。需要指定參數的顯而易見的地方在於如果模板參數未被推導出來。方便的地方在於何時需要將參數引導至適當轉換的類型。當你想明確指定參數時,你經常不能使用重載。 –

2

對於函數模板專門化,您可以顯式列出模板參數,但是如果推導出模板參數,則不需要。如果不指定模板參數,則編譯器將使用與重載解析相同的規則推導它們。爲了決定選擇哪一個函數重載,編譯器首先只查看主模板(首先由某個神奇進程選擇)。查看兩個可用的主模板

template <typename T> void foo(T); 
template <typename T> void foo(T*); 

後者更適合指針參數。一旦找到適當的主模板,編譯器就會查找該主模板的潛在特化。然而,你的示例#2實際上並不是函數模板的特殊化,但它需要一個指針參數,儘管它涉及一個指針參數。如果你採取的主要聲明

template <typename T> void foo(T*); 

,你被明確指定模板參數int*取代T

template <> void foo<int*>(int**); 

也就是說,申報

template <> void foo<int*>(int*); 

是不同的東西。你可能只想指定模板參數的時候就失去了指針:

template <> void foo<int>(int*); 
+1

爲什麼你說'#2'不應該編譯?它適合第一個模板,'template void foo(T)'with'T = int *'。 –

+0

@AaronMcDaid哦,對不起,你是對的:我沒有看到有兩個主要模板,問題就變成了這些模板中的哪一個。但是,由於主要匹配的指針版本版本是更好的選擇,因此即使它的特殊性更好匹配,也會選擇此模板:重載解析對主模板有效。一旦功能模板被確定,選擇適當的專業化。我想,我應該編輯答案來反映這... –