2012-08-16 51 views
2

我已經通過VS2010運行以下代碼。爲什麼實現順序在「爲什麼不專用功能模板」中很重要

#include <iostream> 

template<class T> // (a) a base template 
void f(T) 
{ std::cout << "(a)" << std::endll;} 

template<class T> // (b) a second base template, overloads (a) 
void f(T*)  //  (function templates can't be partially 
{ std::cout << "(b)" << std::endll;} 

template<>  // (c) explicit specialization of (b) 
void f<>(int*) 
{ std::cout << "(c)" << std::endll;} 

int main(int argc, char* argv[]) 
{ 
    int *p = new int(10); 
    f(p); // '(c)' 

    return 0; 
} 

/////////////////

#include <iostream> 

template<class T> // (a) same old base template as before 
void f(T) 
{ std::cout << "(a)" << std::endll;} 

template<>  // (c) explicit specialization, this time of (a) 
void f<>(int*) 
{ std::cout << "(c)" << std::endll;} 

template<class T> // (b) a second base template, overloads (a) 
void f(T*) 
{ std::cout << "(b)" << std::endll;} 

int main(int argc, char* argv[]) 
{ 
    int *p = new int(10); 
    f(p); // '(b)' 

    return 0; 
} 

輸出結果是(c)。然而,如果我將(c)代碼塊移到(b)之前,那麼輸出結果是(b)。 我已閱讀相關文章http://www.gotw.ca/publications/mill17.htm這裏。仍然感到困惑。

爲什麼在這種情況下代碼的順序很重要?

+1

在第二種情況下,你爲什麼認爲'(c)'是'(b)'的一個專長?如果是這樣,那麼在主模板之前專業化怎麼樣? – Nawaz 2012-08-16 15:07:16

+0

無論如何,PS應該是'template <> void f (int *)'。我有一個懷疑,你有一個普通的不合格的程序。 – 2012-08-16 15:08:23

+0

@Nawaz,這不是我的評論,它來自香草Sutter – q0987 2012-08-16 16:01:10

回答

2

我認爲你已經掌握了大部分的信息。問題是有兩個基本模板是重載的,否則不相關。

如果在只聲明瞭第一個特化時執行了特化,那麼編譯器會認爲這是專用於T == int*的第一個模板。現在,在聲明瞭兩個模板之後,執行調用時,編譯器只會查看基本模板,並確定第二個模板與表達式匹配的更好。第二個模板沒有專門化,因此使用了基本模板定義。

讓我強調一下:模板專業化只有在他們的基礎模板被選中後才能發揮作用。它們不影響編譯器將選擇的基本模板。

如果將專業化後的第二個模板聲明,編譯器是匹配與T == int第二基地模板專業化。在這種情況下,當編譯器選擇第二個模板作爲main中呼叫的最佳匹配時,專門化將啓動並且您將獲得專門的行爲。

1

正如文章中所解釋的那樣,當您移動專業化時,它會更改正在專用的功能。 (b)之前,你將專業化放在(a)專業上。

template<>  // (c) explicit specialization of (a) <-- here 
void f<>(int*) 
{ cout << "(c)" << endl;} 

在這兩種情況下,當你調用f(p),編譯器做的第一件事就是看(一)和(b),並確定哪些是超載更適合。正如您列出的文章所解釋的,專業化不參與重載解析,所以在這兩個示例中,它挑選(b)。在這一點上,它尋找(b)的任何專業化。

在第一種情況下,由於您有專門的(b)和(c),它會執行(c)。在第二種情況下,由於你沒有專門化(b),它執行(b)。

編輯:阻止訂單提交的最簡單方法是在提供專業化之前轉發聲明(a)和(b)。在這種情況下,編譯器能夠推斷出你的意圖。見第http://ideone.com/qj2JC

+0

所以基本上如果你說'template <> f (int *)',你會明確地專門化第二個模板,'template <> f (int *)'將會專門化第一個...離開爭論只是要求麻煩。 – 2012-08-16 15:38:21

+0

@Dave,仍然來到我原來的Q,代碼是完全一樣的。唯一的區別是訂單。令我感到驚訝的是,編譯器只是簡單地選擇了不同的命令而改變了順序。 – q0987 2012-08-16 16:11:08

+0

@ q0987:那麼,當你聲明(c)時,如果編譯器還沒有意識到(b),那麼專門用於該函數的最佳匹配是(a)。在相同的情況下,您可以在常規重載中獲得相同的問題。 – 2012-08-16 16:35:41

相關問題