Nathan Reed

Blog Stuff I’ve Made Talks About Me
Greg Egan’s Orthogonal: Alternate Physics, Familiar PoliticsHow Is The NDF Really Defined?

C++ Compile-Time Array Size

July 10, 2013 · Coding · Comments

A handy utility to add to your C++ codebase is a way to get the count of elements in an array whose size is known at compile time. This is useful for things like iterating over a static array, or ensuring that the size of an array matches another array or an enum. Most C++ coders have probably seen something like this before, but as it’s not entirely trivial to get right, I thought it was worth a quick blog post.

First, let me state the requirements. I want to define a symbol dim() that, applied to an array, returns the count of elements if the array’s size is known at compile time, and errors out if it’s not (or if the thing isn’t an array). So this:

int array[] = { 27, 47, 74 };
cout << dim(array);

should output “3”.

One way I’ve seen to do this is as a macro:

#define dim(x) (sizeof(x) / sizeof((x)[0]))

That does the job—it calculates the size of the whole array, divided by the size of one element. The trouble is it’s not type-safe! It can be applied not just to compile-time arrays, but to any type that’s subscriptable. In particular, it can be applied to pointers and to containers like std::vector, and will happily give you a bogus result in either case.

So let’s try to make a type-safe version. We can do this using templates, by writing a function that only accepts arrays as a parameter:

template <typename T, int N>
int dim(T(&)[N])
{
    return N;
}

That horrible T(&)[N] notation is a reference to an (unnamed) array. Note that it doesn’t need to be a const-reference because in C++ there is no distinction between an array being const and its elements being const, so the T type parameter can absorb any constness.

This version works fine at runtime, but it doesn’t work at compile time! A C++ compiler won’t let you use this function in contexts where a compile-time constant expression is required, such as in static_assert or as the size of another array.

Now if we’re in a compiler that supports the C++11 constexpr feature, we can just declare dim as constexpr in there and all will be well. But Visual Studio doesn’t support constexpr (boo, hiss). Fortunately, there’s another workaround! I learned the following trick from a coworker at Sucker Punch, and it’s also used in the Windows headers:

template <typename T, int N> char(&dim_helper(T(&)[N]))[N];
#define dim(x) (sizeof(dim_helper(x)))

This combines both approaches: a template function to ensure type safety and a macro using sizeof to make a compile-time constant expression. The horrible mess of syntax char(&dim_helper(T(&)[N]))[N] declares a function that takes a reference to an array of T, and returns a reference to an array of char of the same size. The function only needs to be declared—there’s no need for a body, since sizeof only looks at the return type and doesn’t actually evaluate the function. And since sizeof(char) == 1, the size of the returned array will be the desired count of elements.

Tweet
Greg Egan’s Orthogonal: Alternate Physics, Familiar PoliticsHow Is The NDF Really Defined?

Comments on “C++ Compile-Time Array Size”

Subscribe

  • Follow in Feedly Feedly
  • RSS RSS

Recent Posts

  • Reading Veach’s Thesis, Part 2
  • Reading Veach’s Thesis
  • Texture Gathers and Coordinate Precision
  • git-partial-submodule
  • Slope Space in BRDF Theory
  • Hash Functions for GPU Rendering
  • All Posts

Categories

  • Graphics(32)
  • Coding(23)
  • Math(21)
  • GPU(15)
  • Physics(6)
  • Eye Candy(4)
© 2007–2023 by Nathan Reed. Licensed CC-BY-4.0.