2011-03-28 72 views
5

請看下面的測試代碼:選擇具有指針參數

template<class T> struct Wrap {}; 

template<typename T> inline 
void fun (T *&Int)   // **choice 1** 
{} 

template<typename T> inline 
void fun (Wrap<T> *&Int) // **choice 2** 
{} 

int main() 
{ 
    int i = 6; 
    fun((char*&)(i));   // **call 1** 
    fun((Wrap<char>*&)(i)); // **call 2** 
} 

當我運行在Linux G ++這段代碼,它的工作原理按預期。當使用char * &調用fun()時,它會直接調用choice 1的函數。然而,當我們調用fun()與包裝< char> * &並且它調用了選項2時,我感興趣。儘管選項1和2對於第二次調用都有效,編譯器仍然設法選擇一些更好的競爭者 - > choice 2(因爲它存在)。

問題:是否保證,對於任何其他C++編譯器都會保留相同的行爲?如果不是,那麼是否有其他選擇使其具有確定性?

+0

'inline'在模板函數中幾乎沒有用處。這不是必須的,因爲它們是(非專用的)模板,因此不會導致鏈接器錯誤,編譯器比我們更好地確定何時內聯和何時不內...並可能完全忽略您的請求。 – 2011-03-28 09:12:43

回答

2

雖然代碼可能看起來像一個模板專業化,事實並非如此。該語言不允許部分模板功能專業化。這兩個是不相關的模板,恰巧是重載。

編譯器將調用查找高達fun((Wrap<char>*&) i)與通常的查找機制,會發現兩個模板,並確定有兩個潛在的重載:然後

template <typename T> void fun(T*&);  // with T == Wrap<char> 
template <typename T> void fun(Wrap<T>*&) // with T == char 

重載決策將決定第二個是更好的匹配並實例化它。這是由標準保證的,但要注意:它們不是相同的模板,而是不同的模板,可能會遇到未預期的結果。看文章@LiKao鏈接更多的見解。

3

對規範有更好的瞭解的人可以證實這一點,但我相信Wrap<T>是一個比簡單T更具體的類型,在所有平臺編譯器上,call 2總是會解決爲'choice 2'。

+1

除非有編譯器的bug;) – 2011-03-28 07:32:22

+0

編譯器bug!?從來沒有聽說過一個...... :) – 2011-03-28 21:55:14

6

選擇第二選擇,因爲它比那是第一代更加專業化,T*&可以綁定到任何非臨時T*,但Wrap<T>*&只能綁定到一個非暫時性的Wrap<T>*。就我所知,這是標準的,應該是可移植的行爲,但在實踐中,什麼是和什麼是不可移植的,對於這類事情通常不是什麼標準的定義。

+3

它實際上是可移植的,但它們不是模板的特化,而是兩個分開的模板,它們恰好是重載。 – 2011-03-28 08:06:06

1

有一件事情可能使這個問題變得更加嚴重,專業模板類和模板函數的規則差異很大。這是爲了重載模板函數的可能性,而不能重載類。因爲我不是對這個話題如此堅定我只是鏈接到的人誰是能夠解釋更深入:

Herb Sutter: "Why Not Specialize Function Templates?"

+1

這不是專業化,而是過載。專業化將有一個模板參數列表出現在函數標識符和函數參數之間(以及在模板之後出現的空模板參數列表,因爲函數特化必須是完全專業化的)。 – 2011-03-28 09:11:15