2013-05-31 129 views
10

令我驚訝的這個節目在這兩個MSCV和GCC編譯:方法名稱相同,C++模板方法名稱++

class A 
{ 
public: 
    int add() { return 0; } 
    template<typename T> 
    T add() { return T(); } 
}; 

int main() { 
    A a; 
    a.add(); 
    a.add<int>(); 
    return 0; 
} 

顯然,由於該模板方法的類型不能被推斷,需要要明確說明,所以情況並非模糊不清 - 但它似乎有點陰暗 - 如果它是一種非模板化的方法,顯然是不正確的。

我試過Google搜索並查看了標準的最後草稿,但找不到答案 - 是模板方法和普通方法的相同命名,它們僅在C++中與返回類型合法不同,或者是編譯器只是寬容嗎?

回答

10

這一直是合法的C++。

14.5.6/2:

函數模板可以與其他功能模板和與正常(非模板)函數被重載。普通函數與函數模板無關(即從未被認爲是專業化),即使它與潛在生成的函數模板專用具有相同的名稱和類型。

當使用「template-id」語法(如add<int>)時,只考慮具有足夠模板參數的模板函數。因此a.add<int>()甚至不會查看非模板add是否匹配。

當一個標識符同時命名一個普通函數和一個函數模板時,編譯器將嘗試推導函數模板的模板參數以獲得模板函數特化。然後,所有普通函數和所有模板函數專門化都通過常用的函數重載邏輯進行比較。 [見13.3.1/7。]

在您的示例中,呼叫a.add()無法爲模板版本推導出模板參數T。所以唯一可行的功能是非模板過載。

還有一個類似情況出現的規則:如果一個非模板函數和一個模板函數專門化否則會是一個模糊的重載,則非模板函數會獲勝。 [此規則在第13.3.3節中,是什麼使一個功能比另一個更好地爲一組給定的參數定義的中間。]

class B 
{ 
public: 
    int f(int n) { return n+1; } 

    template<typename T> 
    T f(T n) { return n; } 
}; 

int main() { 
    B b; 
    b.f(1);  // both are viable, non-template wins 
    b.f<int>(1); // only the template is viable 
    return 0; 
} 

這是有道理的,因爲模板仍然可以通過使用其他專業,或明確使用<尖括號>。因此,使用非模板函數重載函數模板有點類似於添加明確的特化,但頭痛較少。

+0

哇,後者更有趣 - 將記住這一點,謝謝! –