2010-05-31 39 views
2

尋找一種方法可以做到便攜,安全,元素計數C風格的數組,我發現這個解決方案:是便攜式的函數引用sizeof?

template <typename T, unsigned N> char (&arrayCountofHelper(T(&)[N]))[N]; 
#define ARRAY_COUNTOF(arr) (sizeof(arrayCountofHelper(arr))) 

好像arrayCountofHelper實際上是一個函數的引用,和宏ARRAY_COUNTOF用途一個函數的大小是它的返回類型的大小這一事實。
它工作得很好。
但是,當我試圖檢查它是否可移植時,我沒有找到任何證據。我無法在標準(14882/1998)中找到對sizeof(函數引用)的任何引用,事實上,我不完全確定我可以甚至創建一個函數引用(儘管標準提到了幾個次)。
那麼,有人知道我應該看什麼標準嗎? (或者,如果我誤解了聲明一些如何,什麼是正確的解釋?)

感謝
奧倫

附: (對於那些你們誰認爲我沒有找到我的問題的合適的解決方案)
我知道我可以隨時使用

#define ARRAY_COUNTOF sizeof(arr)/sizeof(arr[0]) 

甚至

template <typename T, unsigned N> size_t arrayCountof(T(&)[N]) {return N;} 

,但首先會不會檢查arr是一個數組(或指針),第二個在static_assert內不可用。
(我會使用的std :: TR1 ::陣列或std ::矢量,但是這是一箇舊的代碼我維持)

+2

查看此答案的其他解釋:http://stackoverflow.com/questions/437150/can-someone-explain-this-template-code-that-gives-me-the-size-of-an-array/437178#437178(底部) – 2010-05-31 20:27:58

回答

4

我們將寬鬆地選擇這個,我使用INCITS + ISO + IEC + 14882-2003。我會引用小東西,但一些更復雜的東西太大而不能引用。

sizeof在第5.3.3節所定義,並且它說(刪節):

sizeof運算產生在其操作數的對象表示的字節數。操作數可以是一個表達式,它不會被評估,或者是一個帶括號的類型標識符。

換句話說,它以字節爲單位產生一個類型的大小,或者找到一個表達式的類型併產生一個表達式的大小。我們沒有類型,我們有表達式arrayCountofHelper(arr)

您可以通過查看分別在§5.1和§5.2中定義的primary-expressionpostfix-expression的定義來剖析此表達式。你會發現它是一個postfix-expression並符合函數調用的要求(第5.2.2節)。

現在回到sizeof。我們只關心這個函數調用表達式的類型(所以我們可以產生它的大小)和§5.2。2/3說:

函數調用表達式的類型是靜態選擇函數[...]的返回類型。該類型應爲完整的對象類型,引用類型或類型void

所以我們需要找到將被調用的函數的返回類型(請記住,這是所有未評估)與arrayCountofHelper(arr)arrayCountofHelper是一個函數模板,我們將實例化(第14.7節),所以我們需要這樣做,然後才能獲得返回類型的實例化函數。

所有模板參數都需要有值(第14.8.2節),並且通過使用第14.8.2.1節中定義的規則,我們將通過將傳遞給該函數的數組與匹配函數參數(其中是對數組的引用)。 (例如,如果arrint[10],T將是int並且N將是10.)一旦我們有了這些,函數就可以被實例化。

一旦實例化,函數的返回類型將是char(&)[N] *,該參數是對數組Nchar的數組。 (如果需要幫助解析,請參閱第8.3.5節。關於如何解析「複雜」類型,還有關於SO的問題。)現在我們已經找到了表達式的類型,我們必須考慮它的大小。

第5.3.3節/ 2定義如何sizeof作品與參考文獻和陣列(重點煤礦):

當施加到一個參考或引用類型,其結果是被引用類型的大小。當應用於類時,結果是該類的對象中的字節數,包括將該類型的對象放入數組所需的任何填充。大多數派生類的大小應大於零(1.8)。將sizeof應用於基類子對象的結果是基類類型的大小。70)應用於數組時,結果是數組中的字節總數。這意味着n個元素數組的大小是元素大小的n倍。

引用類型的大小是其引用類型的大小,所以我們需要的char[N]大小。這個尺寸是N * sizeof(char)char是最基本的,因爲它是最小的類型;也就是sizeof(char)總是其中之一。 (§5.3.3/ 1)所以這個表達式產生的大小是1 * N,或者我們想要的全部時間:N

這就是它的工作原理。


這一個優於的arrayCountof你的最後一個例子的原因是因爲的sizeof結果是常量表達式,這樣可以在需要的常量表達式地方使用。

應當指出的是,C++ 0x中,我們可以得到我們的清潔無宏觀語法有:

template <typename T, unsigned N> 
constexpr size_t arrayCountof(T(&)[N]) {return N;} 

*究其原因,函數的返回類型是一個數組的引用而不是一個數組,因爲你不能返回數組。如果可以的話,任何選擇都可以。

+2

+1 :)通過說'template typename identity :: type&arrayCountofHelper(T(&)[N]);':)我可以看到更好的整體雖然sizeof運算符的描述很奇怪,因爲表達式從來沒有引用類型,因爲'5/6'(所以'sizeof'運算符得到的表達式的類型是'char [N]'),所以它應該指定「適用於引用類型時,結果是引用類型的大小」 - 不提及引用。最後,由於引用閃耀,無論如何,它無所謂:) – 2010-05-31 20:37:05

+0

W哇,所以應該真的加上這個+100按鈕:)謝謝! – 2010-06-01 08:19:02

2

奧倫

這不是一個函數引用。這是一個函數調用表達式,它有一個類型 - 結果的類型。 Sizeof可以應用於任何具有類型的表達式。