2013-04-08 125 views
22

在回答this SO question,我的標準中(已C++ 03,仍然在C++ 11),如果他們是你只能使用地址作爲非類型模板參數形式& id-expression(加上一些例外)。指針作爲非類型模板參數

但我不能回答爲什麼是這種情況。

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

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

[...]

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

(n3485,重點煤礦)

例子:

using TFoobar = int (*)(); 
template < TFoobar tp > struct foo_struct{}; 

int foobar() { return 42; } 
constexpr TFoobar pFoobar = &foobar; 

foo_struct < &foobar > o0; // fine 
foo_struct <pFoobar> o1; // ill-formed 

我猜它是與翻譯階段,即編譯器不知道多少關於地址。但是,爲什麼不允許?編譯器是否可以使用類似於宏替換的東西來替換與&foobar

+1

非常好的問題。 – 2013-04-08 17:38:54

+1

我想這是一個保守的改變。爲了讓編譯器實現者更容易,C++ 11充滿了真正嚴格的語言工作方式。有可能擴展C++ 11以支持上述內容,但這是C++ 14或更高版本的問題! – Yakk 2013-04-08 17:40:35

+0

[有建議](http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n4268.html)刪除這些限制。 – dyp 2015-01-01 21:14:56

回答

1

考慮類別Foo<&X>Foo<&Y>,兩者均使用靜態成員int Bar。鏈接程序必須能夠判斷您的程序是否有1個或2個Bar對象。現在考慮鏈接器也是最有可能負責將值分配給&X&Y的一方。

在標準再看看。在編寫時,編譯器不需要將實際的地址傳遞給鏈接器。相反,它通過了id-expression。即使在給它們分配一個數字地址之前,連接器已經能夠確定兩個id-expression是否相同。

+1

我知道替代品可以用來代替實際的地址。但是,這怎麼回答我的問題,爲什麼'constexpr'對象不能用作指針模板參數? – dyp 2013-04-09 19:56:13

+0

而且,要添加到DyP註釋中,如果有一個指向函數的constexpr指針,它的值可以被計算並傳遞給鏈接器('&id'或'nullptr')(以及更多:這與您的答案不矛盾)。 – Synxis 2013-04-09 21:36:52

+0

@Synxis:不,編譯器無法計算(constexpr)指針函數的值,因爲鏈接器將爲函數提供其地址。 – MSalters 2013-04-10 15:19:01

0
  1. 它不能是一個變量,因爲變量只在運行時設置。
  2. 它不能是一個constexpr,由於地址的不能在編譯時已知的;在大多數情況下,只有在執行前重新安置後才能修復。
  3. 理論上它可能是一個算術表達式(儘管它在標準中不允許),但在數組元素地址的常見情況下,您可以簡單地使用&arr[i]而不是arr + i
+0

什麼不能成爲constexpr?函數地址在編譯時已知(包括鏈接時間)。此外,重定位主要發生在共享庫上,在現代系統中,「exe」通常不會被重新定位。 – Synxis 2013-04-09 21:32:43

+0

廣告3:標準中允許使用常量表達式,如果我正確解釋它;它只是禁止函數(函數ptrs)。雖然我可以理解爲什麼算術表達式對函數ptr沒有多大意義,但對函數ptr求值的常量表達式對我來說確實有意義,請參閱OP(或Synxis原始問題)中的示例。 – dyp 2013-04-11 11:24:29