2013-04-07 62 views
8

之間的差異在回答this question,我嘗試用gcc下面的代碼(code compiled)和鐺(code rejected):靜態constexpr指針到函數,編譯器

typedef long (*func)(int); 

long function(int) { return 42; } 

struct Test 
{ 
    static constexpr func f = &function; 
}; 

template<func c> 
struct Call 
{ 
    static void f() 
    { 
     c(0); 
    } 
}; 

int main() 
{ 
    Call<Test::f>::f(); 
} 

我不知道哪個編譯器是正確的,雖然我認爲Test::f的constexpr初始化是可以的。錯誤鐺輸出是:

error: non-type template argument for template parameter of pointer type 'func' 
     (aka 'long (*)(int)') must have its address taken 
  1. 哪個編譯器是正確的?
  2. 如果clang是對的,爲什麼,這個錯誤真的意味着什麼?

編輯:對於「爲什麼」,請參閱DyP's question

+0

我想知道是否'&function'實際上是'constexpr'有效的初始化。兩個編譯器似乎都這麼認爲。但它似乎對我來說很不好。這隻在編譯時才知道,僅在鏈接時。 – Omnifarious 2013-04-07 20:34:54

+0

'&function'是一個函數的地址,所以對我來說它在編譯時是已知的...例如,你可以傳遞一個指針作爲模板參數。 – Synxis 2013-04-07 20:37:45

+1

指向函數的指針是一回事......如果這是共享庫的一部分,例如,該地址如何可能符合「constexpr」? – 2013-04-07 20:46:53

回答

8

14.3.2模板非類型參數[temp.arg.nontype]

模板參數的用於非類型的,非模板的模板參數應是以下之一:

[...]

- 一個常量表達式(5.19),其指定具有靜態存儲>持續時間和外部或內部聯動或與外部或內部聯動,包括功能模板和模板功能的功能的對象的地址 - 但不包括除非&如果名稱引用函數或數組,則可以省略,並且如果相應的模板參數是引用,則可以省略;除非可以省略否定靜態類成員(忽略小括號)& id-表達式。 [...]

(n3485,重點煤礦)

我不知道到底爲什麼它是有限的,但我認爲這可能與這樣的事實:該函數的地址是不可用編譯時間(可能會替代模板實例目的)。


編輯:增強的答案因處Synxis

的後續問題(評論)
constexpr func = &function; 

^這是很好形成;您可以使用函數的地址來初始化一個constexpr對象。 的問題是,它明確禁止使用指針作爲比形式&identifier的其他非類型模板參數:

using My_Call  = Call < &function >; // fine 

constexpr func mypointer = &function; // fine 
using My_Ind_Call = Call <func>;  // forbidden, argument not of form `&id` 
+3

這似乎是一個疏忽。如果你將一個'constexpr'分配給'constexpr',然後把它分配給另一個'constexpr',它應該是可傳遞的。 – Omnifarious 2013-04-07 20:57:15

+3

@Omnifarious它**是**一個'constexpr'。但它被明確禁止作爲模板非類型參數。 – dyp 2013-04-07 21:04:41

+0

嗯,這很有趣。顯然沒有正交處理。我不知道推理是什麼。雖然,我有強烈的懷疑。我的猜測是,鏈接器可以重定位的對象在模板的移動規則中通過名稱引用。要求編譯器爲'constexpr'這樣的東西提供原始名稱是相當麻煩的,並且在某些情況下可能是不可能的。 – Omnifarious 2013-04-08 14:05:19