Introduction
Array size macros in C++ are typically ported from C, and so often end up looking something like this.
#define ARRAY_SIZE_UNSAFE(A) (sizeof(A)/sizeof(*(A)))
This will work, however it has no type safety, so you can pass it both an array or a pointer to an array.
This post shows how templates can be used in C++ to create a safer array size macro (this is the same technique that _countof uses in MSVC).
The Code
The test case for our array size macro is shown below. The first usage should compile and produce the correct result (as a compile time constant), the second usage should fail to compile.
const int arr[] = { 0, 1, 2, 3, 4 };
const int *const ptrToArr = arr;
ARRAY_SIZE(arr);
ARRAY_SIZE(ptrToArr);
The implementation of ARRAY_SIZE
is as follows.
#define ARRAY_SIZE(A) (sizeof(ArraySizeHelper(A)))
template <typename T, size_t N>
char (&ArraySizeHelper(T (&a)[N]))[N];
I’ll admit that the syntax looks like a confusing mess, so let’s break it down a bit.
ArraySizeHelper
is a function declaration (it doesn’t need a definition), which takes a reference to any type of array; in my test case above, “T” would be “int”, and “N” would be 5.- The return type of
ArraySizeHelper
is a reference to an array of type “char” the same size as the array passed into the function; in my test case, this produces a return value of “char[5]“. - The
ARRAY_SIZE
macro then takes the size of the return type of the function (which is a compile time constant); “sizeof(char[5])” is 5, which is the correct size for my array.
While this may seem like overkill just to get the size of an array, the bonus is that as ArraySizeHelper only accepts a reference to an array, trying to pass “ptrToArr” produces a compiler error, which is exactly the behaviour we want.
A much more detailed explanation of how this function works is available on the MSDN blog.
comments powered by Disqus