2010-09-04 85 views
20

爲什麼這個編譯失敗? (克++ - 4.5)C++模板函數的地址

template < typename U > 
static void h() { 
} 

int main() { 
    auto p = &h<int>; // error: p has incomplete type 
} 

EDIT:這裏是一個變通:

template < typename U > 
static void h() { 
} 

int main() { 
    typedef decltype (&h<int>) D; 
    D p = &h<int>; // works 
} 
+1

在Visual Studio 2010上編譯得很好。這很可能是GCC中的一個小故障。你可以嘗試的是'decltype(&h )p =&h ;' – Puppy 2010-09-04 09:53:30

+0

至少可以和G ++ 4.6一起使用。 – Maister 2010-09-12 10:38:17

+0

@DeadMG:如果沒有「auto」,甚至不需要typedef,'void(* p)()=&h ;'也會編譯。 – doc 2010-09-12 15:34:47

回答

13

在C++ 0x中,這是保證工作。然而,在C++ 03中,這不起作用(即初始化部分),有些編譯器顯然不支持它。另外,我記得C++ 0x的寫法並不清楚&h<int>是什麼,當它是一個函數模板的參數並且推導出相應的參數(這是auto被轉換爲概念性的)。然而,它的意圖是有效的。見this defect report他們在那裏設計的措辭,「尼科Josuttis」的例子和他們的最後一個例子。

還有另一個規則,措辭強制執行但編譯器沒有正確執行。例如,see this clang PR

0

它不編譯,因爲 'P' 的類型是未知的編譯器,其是必須的在C++不像其他一些語言。

嘗試

template < typename U > 
static void h() { 
} 

int main() { 
    auto void (*p)() = &h<int>; 
} 
+1

'auto'關鍵字用於自動類型扣除。一個C++ 0x功能。 – dirkgently 2010-09-04 09:39:34

+0

好的,但在我的真實代碼中,h取決於U和其他模板需要很多其他參數,我不想全部指定它們,因爲編譯器應該知道p的類型。 – Thomas 2010-09-04 09:40:43

+1

@dirkgenly:哦。我仍然在C++ 03其中'自動'用於自動變量 – Chubsdad 2010-09-04 09:41:29

0

嘗試

auto p = static_cast<void(*)()>(& h<int>); 

因爲gcc對待模板用作重載之一。從海灣合作委員會的角度來看,它就像你會有h(int param)h(float param) - 編譯器必須選擇哪一個?

我注意到舊版本的gcc有什麼問題,但我會試着更詳細地解釋它。 GCC無法推斷出該類型,因爲模板化函數被視爲超載。這基本上就像你具備以下條件:

void h(int) 
{ 
} 

void h(float) 
{ 
} 

void (*p)(int) = & h; //ok 
void (*p)(float) = & h; //ok 
auto p = & h; //error: which version of h? 

海合會h<int>簡直就像重載h函數依賴於T參數無盡的替代品。有問題的代碼是O.K.做到以下幾點:

void (*p)() = & h<int>; 

(這就是爲什麼我沒有得到通過typedef「變通」)

,因爲我以爲OP想用C++ 11 auto通過關鍵字標籤的建議,我靜態鑄造了h<int>void(*)(),這是一種無操作,只是爲了欺騙gcc,因爲它無法正確處理模板化函數和auto

函數void h<int>()void h<float>()當然應該被當作具有相同指針類型的不同函數處理,而不是h函數的超載版本。實例化時,他們應該表現得像void hInt()void hFloat(),你應該能夠使用自動喜歡這裏:

void hInt() 
{ 
} 

void hFloat() 
{ 
} 

auto p = hInt; 
p = hFloat; 

但由於某些原因海合會他們喜歡的h重載版本。

請給出downvotes的原因。

+0

我不是downvoter :)無論如何,我不知道你的邏輯理解:因爲你是static_casting編譯時間已知的類型,有什麼用於汽車? – Francesco 2010-09-12 10:22:08

+0

@Francesco:沒有轉換gcc會拋出一個錯誤「語句無法解析重載函數的地址」。在重載函數的情況下(例如'void h(int)'和'void h(float)'),您將得到相同的錯誤,在這種情況下,編譯器在找到'&h'語句時無法確定選擇哪個版本。出於某種原因(我認爲這是模板參數發現的事情),模板化函數的處理方式與重載的函數相同。在使用static_cast之後,就像在重載函數的情況下一樣,它開始編譯。 'auto'用於推導'p'類型。 – doc 2010-09-12 15:24:42

+0

@Francesco:他們用'typedef'獲得了與static_cast相同的結果。我以爲他想要C++ 0x'auto'關鍵字... – doc 2010-09-12 15:32:35