Use Templates to Get an Array's Size and End Address

Use templates to get an array's size and end address

struct Foo
{
template< typename T, size_t N >
Foo(T(&array)[N]) : ptr(array), size(N) { }

const char* ptr;
size_t size;
};

array is a reference to an array of N T's. The same is true of the original code, but the parameter isn't given a name.

But this really isn't calculating the address at compile time. If you think about it, you'll realize this is impossible. If stack addresses were fixed, recursion (and many other algorithms) could never work.

Note that the last line:

Foo foo3(baz);

still won't work because baz is a pointer not an array.

How to get size of an array using metaprogramming?

For one dimensional Arrays,

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

int arr[]={1,2,2,3,4,4,4,54,5};
cout << size_of_array(arr) << endl;

A a[] = {A(),A(), A(), A(), A()};
cout << size_of_array(a) << endl;

Output:

9
5

Full Demo at Ideone : http://ideone.com/tpWk8


EDIT:

Another way (after seeing your edit),

template<typename T>
struct get_dim;

template<typename T, size_t N>
struct get_dim<T[N]>
{
static const int value = N;
};

int main()
{
cout << get_dim<int[100]>::value;
return 0;
}

Output:

100

http://ideone.com/wdFuz


EDIT:

For two dimensional arrays:

struct size2D
{
size_t X;
size_t Y;
};

template<typename T, size_t M, size_t N>
size2D size_of_array(T (&)[M][N])
{
size2D s = { M, N};
return s;
}
int arr[][5]={ {1,2,2,5,3}, {4,4,4,54,5}} ;
size2D size = size_of_array(arr);
cout << size.X <<", "<< size.Y << endl;

Output:

2, 5

Code : http://ideone.com/2lrUq

How does this Array Size Template Work?

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.

How to access/get the size of an array/collection in velocity templates?

I've never used Velocity, but its VTL reference guide says that calling a method is done using $customer.getAddress() or ${purchase.getTotal()}. So I would use ${myArrayList.size()}.

How do I find the length of an array?

If you mean a C-style array, then you can do something like:

int a[7];
std::cout << "Length of array = " << (sizeof(a)/sizeof(*a)) << std::endl;

This doesn't work on pointers (i.e. it won't work for either of the following):

int *p = new int[7];
std::cout << "Length of array = " << (sizeof(p)/sizeof(*p)) << std::endl;

or:

void func(int *p)
{
std::cout << "Length of array = " << (sizeof(p)/sizeof(*p)) << std::endl;
}

int a[7];
func(a);

In C++, if you want this kind of behavior, then you should be using a container class; probably std::vector.

How does this template code to get the size of an array work?

This is actually a really tough one to explain, but I'll give it a go...

Firstly, dimof tells you the dimension, or number of elements in an array. (I believe "dimension" is the preferred terminology in Windows programming environments).

This is necessary because C++ and C don't give you a native way to determine the size of an array.


Often people assume sizeof(myArray) will work, but that will actually give you the size in memory, rather than the number of elements. Each element probably takes more than 1 byte of memory!

Next, they might try sizeof(myArray) / sizeof(myArray[0]). This would give the size in memory of the array, divided by the size of the first element. It's ok, and widely used in C code. The major problem with this is that it will appear to work if you pass a pointer instead of an array. The size of a pointer in memory will usually be 4 or 8 bytes, even though the thing it points to might be an array of 1000s of elements.


So the next thing to try in C++ is to use templates to force something that only works for arrays, and will give a compiler error on a pointer. It looks like this:

template <typename T, std::size_t N>
std::size_t ArraySize(T (&inputArray)[N])
{
return N;
}
//...
float x[7];
cout << ArraySize(x); // prints "7"

The template will only work with an array. It will deduce the type (not really needed, but has to be there to get the template to work) and the size of the array, then it returns the size. The way the template is written cannot possibly work with a pointer.

Usually you can stop here, and this is in the C++ Standard Libary as std::size.


Warning: below here it gets into hairy language-lawyer territory.


This is pretty cool, but still fails in an obscure edge case:

struct Placeholder {
static float x[8];
};

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

int main()
{
return ArraySize(Placeholder::x);
}

Note that the array x is declared, but not defined. To call a function (i.e. ArraySize) with it, x must be defined.

In function `main':
SO.cpp:(.text+0x5): undefined reference to `Placeholder::x'
collect2: error: ld returned 1 exit status

You can't link this.


The code you have in the question is a way around that. Instead of actually calling a function, we declare a function that returns an object of exactly the right size. Then we use the sizeof trick on that.

It looks like we call the function, but sizeof is purely a compile time construct, so the function never actually gets called.

template <typename T, size_t N>
char(&DimofSizeHelper(T(&array)[N]))[N];
^^^^ ^ ^^^
// a function that returns a reference to array of N chars - the size of this array in memory will be exactly N bytes

Note you can't actually return an array from a function, but you can return a reference to an array.

Then DimofSizeHelper(myArray) is an expression whose type is an array on N chars. The expression doesn't actually have to be runable, but it makes sense at compile time.

Therefore sizeof(DimofSizeHelper(myArray)) will tell you the size at compile time of what you would get if you did actually call the function. Even though we don't actually call it.

Austin Powers Cross-Eyed


Don't worry if that last block didn't make any sense. It's a bizarre trick to work around a bizarre edge case. This is why you don't write this sort of code yourself, and let library implementers worry about this sort of nonsense.

How do I determine the size of my array in C?

Executive summary:

int a[17];
size_t n = sizeof(a)/sizeof(a[0]);

Full answer:

To determine the size of your array in bytes, you can use the sizeof
operator:

int a[17];
size_t n = sizeof(a);

On my computer, ints are 4 bytes long, so n is 68.

To determine the number of elements in the array, we can divide
the total size of the array by the size of the array element.
You could do this with the type, like this:

int a[17];
size_t n = sizeof(a) / sizeof(int);

and get the proper answer (68 / 4 = 17), but if the type of
a changed you would have a nasty bug if you forgot to change
the sizeof(int) as well.

So the preferred divisor is sizeof(a[0]) or the equivalent sizeof(*a), the size of the first element of the array.

int a[17];
size_t n = sizeof(a) / sizeof(a[0]);

Another advantage is that you can now easily parameterize
the array name in a macro and get:

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

int a[17];
size_t n = NELEMS(a);

Size of an Array.... in C/C++?

The signature of that function is not that of a function taking an array, but rather a pointer to int. You cannot obtain the size of the array within the function, and will have to pass it as an extra argument to the function.

If you are allowed to change the signature of the function there are different alternatives:

C/C++ (simple):

void f( int *data, int size );             // function
f( array, sizeof array/sizeof array[0] ); // caller code

C++:

template <int N>
void f( int (&array)[N] ); // Inside f, size N embedded in type
f( array ); // caller code

C++ (though a dispatch):

template <int N>
void f( int (&array)[N] ) { // Dispatcher
f( array, N );
}
void f( int *array, int size ); // Actual function, as per option 1
f( array ); // Compiler processes the type as per 2


Related Topics



Leave a reply



Submit