sizeof(arr)/sizeof(arr[0]) 的缺陷傳統巨集:
#define DIM(a) (sizeof(a)/sizeof(a[0]))
兩大隱患:
std::vector 等重載 operator[] 的物件,編譯器不報錯,產生無意義結果。內建陣列支援 a[i] == i[a],但自定義 operator[] 不支援。修改巨集:
#define DIM(a) (sizeof(a)/sizeof(0[a]))
傳入 vector 時 0[vec] 編譯失效,解決問題一。但指標問題依然存在。
template
inline size_t DimensionOf(T (&arr)[N]) { return N; }
N 由編譯器自動推導,零成本。size_t 執行期值,非編譯期常數,無法用於 int arr2[DimensionOf(arr)] 或樣板參數。sizeof 編譯期求值 + 輔助結構體
template
struct dimension_help_struct { unsigned char uc[N]; };
template
const dimension_help_struct& make_dimension_help_struct(T (&arr)[N]);
#define DIM(a) (sizeof(make_dimension_help_struct(a).uc))
make_dimension_help_struct 僅需宣告,無需定義(sizeof 不求值)。dimension_help_struct 參考,.uc 陣列大小為 N,sizeof 得 N。unsigned char uc[N] 保證)。
template
unsigned char (&dimension_help_fun(T (&arr)[N]))[N];
#define DIM(a) (sizeof(dimension_help_fun(a)))
unsigned char (&)[N] 陣列參考。sizeof 作用於該陣列參考,得 N。
int is[] = {1, 2, 3};
int* pi = is;
std::vector vi;
DIM(is); // 3 ✓
DIM(vi); // 編譯錯誤 ✓
DIM(pi); // 編譯錯誤 ✓
// 編譯期常數用法
int is2[DIM(is)]; // ✓
std::array a; // ✓ (C++11)
sizeof 技巧 → 極簡輔助函式,橫跨 3 年,見證 C++ 型別系統的表達力與複雜度。現代 C++(C++17 起)可直接使用 std::size(arr)(<iterator>),但理解演進過程有助於掌握樣板元編程核心思想。