19

I've come came across this snippet in the article PVS-Studio vs Chromium

template <typename T, size_t N>  
char (&ArraySizeHelper(T (&array)[N]))[N];  
#define arraysize(array) (sizeof(ArraySizeHelper(array))) 

I've seen other templates to do the same thing, like Use templates to get an array's size and end address.

I understand those, but I've been having difficulty with this one.

6
  • What in particular are you having difficulty with? There are lots of distinct elements of C++ at work here. Commented Jun 16, 2011 at 17:30
  • dupe. Also see the explanation at the bottom of this: stackoverflow.com/questions/437150/… (that's not the dupe, I'm too lazy to search it now). Commented Jun 16, 2011 at 17:56
  • Link to the dupe or it didn't happen :) I couldn't find the dupe either, otherwise I wouldn't have posted. Commented Jun 16, 2011 at 18:24
  • and the real question why not to use std::extent instead of this ugly macro? Commented Jun 16, 2011 at 18:39
  • Possible duplicate of Magic arguments in function templates Commented Apr 25, 2016 at 13:02

3 Answers 3

11

The function template is named ArraySizeHelper, for a function that takes one argument, a reference to a T [N], and returns a reference to a char [N].

The macro passes your object (let's say it's X obj[M]) as the argument. The compiler infers that T == X and N == M. So it declares a function with a return type of char (&)[M]. The macro then wraps this return value with sizeof, so it's really doing sizeof(char [M]), which is M.

If you give it a non-array type (e.g. a T *), then the template parameter inference will fail.

As @Alf points out below, the advantage of this hybrid template-macro system over the alternative template-only approach is that this gives you a compile-time constant.

Sign up to request clarification or add additional context in comments.

7 Comments

I'll just add about the purpose, namely to get the array size as a compile time constant (which in turn can be used to specify the size of a raw array). As I recall it was a Russian who first came up with this variation. Unfortunately I don't recall the name.
So, I take it, that the function is declared but not defined? The syntax is hard for me to parse.
Thanks, I think it was the syntax for returning char (&)[M] that was throwing me. C/C++ array syntax is awful.
@Gene Bushuyev: Basically that you can use this code in any compiler that follows the 98 standard, but you cannot use your approach unless the compiler implements C++0x features (at the very least decltype and the extent type trait.
|
8

This isn't the nicest way of doing it, but since you're asking: The return type of the template function ArraySizeHelper is char[N], where the argument of the function is a (reference to an) array of size N of type T. Template argument deduction instantiates this template with the matching number N, and so sizeof(char[N]) is just N, which is what you get.

A nicer version could be written as follows. (You need C++11 for constexpr; if you omit it, this will not be a constant expression.)

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

Usage:

int x[20];
array_size(x); // == 20

Update: If you are in C++11, here is another solution that gives a constexpr, thanks to decltype:

#include <type_traits>

template <typename T> struct array_traits;
template <typename T, unsigned int N> struct array_traits<T[N]>
{
   static const unsigned int size = N;
   typedef std::decay<T>::type type;
};

// Usage:
int x[20];
array_traits<decltype(x)>::size; // == 20

If you are in C++17, you can also use std::size to get the size of an array.

13 Comments

so out of curiosity, what do you feel the nicest way of doing it is?
@Jalf: Updated. No compiler macros!
Trouble with that is that it's not constexpr, unlike the macro.
@DeadMG: True. Could we somehow wrap this in a way that doesn't need macros? More importantly, do the two compute different assembler output?
Just put constexpr before your first function template, and array_size(x) will be a constant expression too in C++0x.
|
4

This blog on MSDN precisely describes how it works. Very interesting story. Take a look at it.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.