0

我有一個函數模板,我專門爲特定類型。我無法在特定情況下調用專用版本。爲了說明不爲派生類型調用函數模板專門化

struct Base {}; 
struct Derived : public Base {}; 


template <typename VALTYPE> void FooInternal(VALTYPE&) 
{ 
    std::cout << L"FooInternal template"; 
} 

template<> void FooInternal(Base&) 
{ 
    std::cout << L"FooInternal SPECIAL"; 
} 

現在,如果我建「基地」或「派生」的實例,並稱之爲「FooInternal」,所有的作品我希望

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int x = 7; 
    FooInternal(x); // Calls FooInternal<VALTYPE>() template 

    Base b; 
    FooIntenral(b); // Calls FooInternal<Base>() specialization 

    Derived d; 
    FooInternal(d); // Calls FooInternal<Base>() specialization 

    return 0; 
} 

的這個輸出是

FooInternal template 
FooInternal SPECIAL 
FooInternal SPECIAL 

}

但假設我有這兩個調用美孚之間的中間函數模板內部。在這種情況下,派生類型的模板分辨率好像沿途失敗

// Intermediate template. Just calls FooInternal. 

template<typename VALTYPE> 
void Foo(VALTYPE& val) 
{ 
    FooInternal<VALTYPE>(val); 
} 


// Now repeat the same 3 calls and see what happens with Derived... 

int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int x = 7; 
    Foo(x); // Calls FooInternal<VALTYPE>() template 

    Base b; 
    Foo(b); // Calls FooInternal<Base>() specialization 

    Derived d; 
    Foo(d); // Calls FooInternal<VALTYPE>() template!!! 

    return 0; 
} 

這個程序的輸出是

FooInternal template 
FooInternal SPECIAL 
FooInternal template 

我不明白爲什麼 - 在第三個呼叫「 Foo「不會像調用直接時那樣調用FooInternal的專用版本。在這種情況下,編譯器是否應該理解它是從「Base」派生的?我在這裏錯過了什麼規則?

我正在使用Microsoft Visual Studio 2012 Update 3,如果有問題的話。

-Joe

+0

使用[C++]標籤,您將獲得更多注意力和**語法突出顯示**。 – dyp

+0

你有一個明確的(完全)專用於'Base&',而你在用於調用'FooInternal'的顯式規範中使用的類型是'派生的',而不是'Base'。 – dyp

+0

我意識到我在該調用中使用了Derived。但是這並不能解釋爲什麼當我用Derived直接調用FooInternal時它的工作原理。不應該讓Foo所做的調用最終導致編譯器做出與我直接調用Foo時相同的分辨率? – user2057722

回答

1

你的期望在第一個例子中,顯然也是你的編譯器,是錯誤的。輸出應該是「FooInternal templateFooInternal SPECIALFooInternal模板」。

函數模板專門化對模板參數推導或重載解析完全不做任何事情。只有在沒有看到它的規則碰巧結束了完全相同的模板參數的情況下才會使用它。大多數情況下,當你認爲你想要一個函數模板專業化時,將函數重載(使用另一個模板或使用非模板)會是一個更好的主意。

inline void FooInternal(Base&) 
{ 
    std::cout << L"FooInternal SPECIAL"; 
} 

然後,當然,如果你指定模板參數,所以你要FooInternal永遠不能被稱爲:

// Intermediate template. Just calls FooInternal. 

template<typename VALTYPE> 
void Foo(VALTYPE& val) 
{ 
    FooInternal(val); 
} 

這應該給你什麼你要找的人(在所有的編譯器)。

+0

如果我將這個函數轉化爲一個類(例如函數對象),那麼編譯器(根據C++規則)是否能夠推導出參數並調用函數,正如我在此嘗試的那樣?或者我面臨同樣的問題? 我需要std :: enable_if和std :: is_base_of嗎? – user2057722

+0

@ user2057722 IIRC推導類模板的唯一類型是*部分特化*。對於顯式(完整)專業化沒有任何推導。你可以通過'enable_if'和'is_base_of'使用SFINAE來選擇一個*部分特化*(對於類模板),這可能「解決」你的問題(儘管我同意aschepler重載函數模板更容易)。 – dyp

+0

目前還不清楚你對這個問題的含義。 – aschepler