[心得] sizeof_array

看板C_and_CPP作者 (最愛朴素妍)時間13年前 (2010/09/12 03:36), 編輯推噓8(8024)
留言32則, 8人參與, 最新討論串1/1
爬了之前的文章, 發現在算陣列元素個數的時候, 雖然使用 size- of 是很方便~ 不過常會有指標錯用的情形! @_@ template<typename ElementType, size_t ARRAY_SIZE> size_t sizeof_array( ElementType (&)[ ARRAY_SIZE ] ) { return ARRAY_SIZE; } 以上函式模板使用引數推導可以容易取得陣列大小, 雖然解決了這 個問題, 但是下面的程式碼 : int iArray[] = { 1, 2, 3 }; bool bArray[ sizeof_array(iArray) ]; 實際上 bArray是一個 VLA, gcc 加上選項 -Wvla 就會出現 : [Warning] variable length array 'bArray' is used 這樣便無法將陣列以參考的形式傳遞給函式, 來減少參數的個數, 也不能給予特定元素初始值, 如果用來當作 std::array 的模板引 數, 也會出現下列訊息 : 'sizeof_array(ElementType (&)[ARRAY_SIZE])' cannot appear in a constant-expression 因為這個版本的 sizeof_array 是執行時期才回傳值, 實用性顯得 低了些, 解決方案之一是在回傳值之前加上 constexpr關鍵字, 不 過因為 gcc還沒實作出這個功能, VC2010不支援, 所以還請各位看 我娓娓道來 > <, 另一個解決方案是使用類別模版, 非常簡單只有 12行 : template <typename Type> struct sizeof_array_impl { static_assert( std::is_array<Type>::value, "this is not an array type" ); }; template <typename ElementType, size_t ARRAY_SIZE> struct sizeof_array_impl<ElementType[ARRAY_SIZE]> { enum { value = ARRAY_SIZE }; }; 為陣列型態提供特化版本, 列舉值 value即是陣列大小, 如果給錯 型態將會具現化泛化的版本, 造成確保失敗, 編譯停止輸出訊息. #define sizeof_array( array )\ sizeof_array_impl<decltype(array)>::value 巨集中搭配decltype關鍵字取得物件的型態, 陣列大小得以在編譯 時期被評估. 以上是小弟淺見, 如有 OP 會自 D, 謝謝觀賞! -- ╭───╮ ╭╮ ╭╮ 非常非常善良的你 ╭──╯ 非常我的你 ──╮╭──╮│──╯╭─╮╭──── ────────── ──╮│╭╮│╰─╮╭─╯│╭╭╮ 曾一瞬間展露笑容的你 ╭──╯╰╯│ │ ─╯╰╯││││ 曾接受我心意的你 ───╯╰──╯ ╯╰─╯╰╰╯ -- ※ 發信站: 批踢踢實業坊(ptt.cc) ◆ From: 140.121.197.115

09/12 12:52, , 1F
話說 VS2005 有引進了 _countof 可以用
09/12 12:52, 1F

09/12 12:53, , 2F
那個東西我沒記錯的話會求出一個 compile-time constant
09/12 12:53, 2F

09/12 12:53, , 3F
你用那玩意試試看
09/12 12:53, 3F

09/12 12:54, , 4F
_countof 的寫法和你一開始那個 sizeof_array 很像
09/12 12:54, 4F

09/12 12:54, , 5F
只是它繞了一圈不呼叫它而用 sizeof() 去求出所要的值出來
09/12 12:54, 5F

09/12 13:28, , 6F
謝謝 L 大提供的, 其實我剛開始實作的時候也是用參數
09/12 13:28, 6F

09/12 13:28, , 7F
匹配 + 檢驗回傳值大小來做, 不過程式碼太長又不好懂
09/12 13:28, 7F

09/12 13:28, , 8F
最後就變成這樣囉~ > <
09/12 13:28, 8F
※ 編輯: loveme00835 來自: 114.45.64.97 (09/12 13:50)

09/12 14:05, , 9F
推研究心得
09/12 14:05, 9F

09/12 15:24, , 10F
太深奧了看不懂 qq
09/12 15:24, 10F

09/12 17:59, , 11F
請問 y 大, 小弟有哪些地方打不夠詳盡嗎@_@?
09/12 17:59, 11F

09/13 00:00, , 12F
看不太懂目的 是因為VLA所以compiler-timr抓不到個數嗎?
09/13 00:00, 12F

09/13 00:14, , 13F
是阿~ 因為VLA的關係, 沒辦法傳陣列參考給函式(模版)
09/13 00:14, 13F
※ 編輯: loveme00835 來自: 140.121.197.115 (09/13 00:19)

09/13 07:11, , 14F
VLA 不是C99的東西嗎? C++有支持那玩意@@?
09/13 07:11, 14F

09/13 09:54, , 15F
一開始說的問題能理解 但大大你說的解決方法還真看不懂@@
09/13 09:54, 15F

09/13 10:59, , 16F
和我說的解法的想法是一樣的 都是需要一個編譯時期常數
09/13 10:59, 16F

09/13 10:59, , 17F
這裡原 PO 是利用 enum 配上 template 來達成而已
09/13 10:59, 17F

09/13 11:00, , 18F
不過我還滿欣賞 _countof 的解法就是了 XD
09/13 11:00, 18F

09/13 17:20, , 19F
_countof 那招比較酷啦! XD
09/13 17:20, 19F

09/13 20:54, , 20F
有點疑問是template argument不應該是compile-time
09/13 20:54, 20F

09/13 20:54, , 21F
就要得知的嗎?那ARRAY_SIZE應該是compile-time constan
09/13 20:54, 21F

09/13 20:54, , 22F
不是嗎??請問小弟想法哪裡有誤@@"
09/13 20:54, 22F
int a[ 10 ]; cout << sizeof_array( a ) << endl; // 使用第一版本 編譯器看到這樣的code會由模版產生類似下面的函式實體出來 size_t sizeof_array( int (&)[ 10 ] ) { return 10; } 雖然數值可以在編譯時期被得知, 但是在使用的時候必須要先呼叫 函式才能拿回這個常數, 要到執行時才能知道陣列大小. ※ 編輯: loveme00835 來自: 140.121.197.115 (09/13 21:18)

09/13 21:45, , 23F
我也是像大大回文想的那樣,但編譯器不會把它inline
09/13 21:45, 23F

09/13 21:46, , 24F
化嗎?這樣就變成了編譯期常數@@"?還是有什麼我沒注意
09/13 21:46, 24F

09/13 21:46, , 25F
注意到.......感謝大大
09/13 21:46, 25F

09/13 23:19, , 26F
gcc下-O3 和 VS2010下/Ox也是不會inline說> <我是不
09/13 23:19, 26F

09/13 23:20, , 27F
知道編譯器什麼時候會決定幫你展開, 不過不同的編譯器
09/13 23:20, 27F

09/13 23:21, , 28F
策略不一樣的話也會讓人理不清頭緒的! 所以如果真的需
09/13 23:21, 28F

09/13 23:21, , 29F
要 inlining 一個函式, 必須知道編譯器「真的」會這
09/13 23:21, 29F

09/13 23:22, , 30F
樣做, 不然就用「一定」會在編譯時期評估值的寫法, 而
09/13 23:22, 30F

09/13 23:22, , 31F
不要用猜的
09/13 23:22, 31F

09/14 00:40, , 32F
推 感謝大大
09/14 00:40, 32F
文章代碼(AID): #1CYze_ci (C_and_CPP)