2013-03-04 170 views
2

鑑於一些聲明:模板與constexpr函數返回參數

template <class T, T t> 
struct foo {}; 

template <class T> 
constexpr T ident(T t) { 
    return t; 
} 

constexpr int bar() { 
    return 0; 
} 

int main(int argc, const char *argv[]) 
{ 
    foo<bool, true> a; 
    foo<int, bar()> b; 
    foo<int, ident(0)> c; 
    foo<int (*)(), bar> d; 

    foo<int(*)(), ident(&bar)> e; // not accepted (gcc 4.7.2 crashes here, even) 

    return 0; 
} 

旁白:有趣的是,這造成了GCC 4.7.2段錯誤。我必須通過我的svn構建一個4.8.0快照來運行它,甚至會得到一個錯誤信息(「必須是具有外部鏈接功能的地址」)...

爲什麼第一個確定,最後一個不允許 - 這不像案件廣告這樣的constexpr嗎?看起來編譯器完全有能力確定哪個函數正在談論,因爲它可以爲其他類型執行。

+0

什麼是錯誤信息?什麼是'巴茲'? – 2013-03-04 13:44:54

+1

啊。下一次,只給我們最小的再生測試案例。並將你的錯誤報告帶給GCC錯誤跟蹤器,好嗎?這是一個ICE。 ** [http://liveworkspace.org/code/2E1cwt$2](http://liveworkspace.org/code/2E1cwt$2)** – sehe 2013-03-04 13:51:57

+0

對我來說,G ++ 4.7給出了:''ident (baz)'不是類型爲'int(*)()'的有效模板參數;它必須是具有外部鏈接的函數的地址「。 – 2013-03-04 13:53:57

回答

1

E的問題在於,對於指向函數指針類型的非類型模板參數,取其地址(14.3.2)必須是有效的。例如,foo<int(*)(), &ident(bar)>無效。因此,即使ident(bar)的返回是指向具有有效外部鏈接的函數的指針,但對於非類型的模板參數,整個表達式無效。如果你從ident(bar)返回0(或nullptr),它將被編譯(也在14.3.2中定義)。

該標準允許您省略指向函數的指針類型的&,但它仍然必須是有效的才能取得它的地址。這就是爲什麼foo<int (*)(), bar>有效,因爲foo<int (*)(), &bar>有效。另一個函數調用B,C(和A)計算爲整型常量,它們落入不同的類別中。

2

這將允許從C++ 17開始;請參閱N4198(以及最近投入C++標準的相應措辭紙N4268)。俚語後備箱在-std=c++1z模式下接受您的代碼。