2015-04-23 26 views
6

考慮下面的代碼來選擇模板版本:C++函數分辨率通過純函數

#include <iostream> 

template<typename T> 
void f(T t) 
{ 
    (void)t; 
    std::cout << "templated f(T)\n"; 
} 

template<typename T> 
void entry(T t) 
{ 
    f(t); 
} 

void f(double d) 
{ 
    (void)d; 
    std::cout << "normal f(double)\n"; 
} 

int main() 
{ 
    double d = 0.0; 
    entry(d); 

    return 0; 
} 

輸出:

模板化的F(T)

我發現這個令人驚訝的,因爲我認爲普通功能將在任何模板版本上進行選擇。爲什麼會發生?

另一件事我而玩弄注意到的是:如果我把正常功能void f(double)模板化void entry(T)函數的代碼將正常調用函數之前,基本上輸出:

正常F​​(雙)

因此,我的另一個問題:爲什麼順序在這個特殊的例子?

回答

7

f是一個從屬名稱,因爲它取決於t,其類型是模板參數。對於依賴名稱的名稱查找規則示於[temp.dep.res]/1:

在解決依賴性的名稱,從以下來源的名稱被認爲是:

  • 聲明是在可見模板的定義點。
  • 來自命名空間的聲明與來自 實例化上下文(14.6.4.1)和來自定義上下文的函數參數類型相關聯。

換句話說,正常的名稱查找裏面的模板只能找到那些模板定義之前已經聲明的名稱(這並不奇怪,因爲它是相同的非模板)。第二個項目符號點允許在找到模板定義後聲明的名稱,但只有在發生ADL時纔會聲明。當參數是基本類型如double時,情況不會如此。

+0

ok,...但是我注意到,模板內部的查找會在模板的聲明之後找到一個名稱,如果它是另一個模板,甚至是具有基本類型(如「double」)的模板的特化。我通過將普通函數更改爲一個專門的模板來檢查它:'template <> void f(double)'。結果是被調用的專用模板,即使它已經超過了調用代碼的聲明點。 – Edenbridge

+0

@Edenbridge名稱查找始終會查找主模板。專業匹配發生在名稱查找之後,並且具有不同的規則:如果在聲明最佳匹配部分專業化之前實例化模板,那麼程序不合格,不需要診斷。如果您有任何疑問,請發表一個單獨的問題。 – Brian

0

當解析entry(T)模板時,f(double)的重載對編譯器不可見。因此,當entry(T)模板被實例化時,它不會參與重載解析。在解決模板實例化上下文中的重載時,這只是一個不明確的規則。爲了考慮超載,在解析模板定義之前,它必須已經在翻譯單元中可見。