Can this macro be converted to a function? - c++

While refactoring code and ridding myself of all those #defines that we're now taught to hate, I came across this beauty used to calculate the number of elements in a structure:
#define STRUCTSIZE(s) (sizeof(s) / sizeof(*s))
Very useful as it is but can it be converted into an inline function or template?
OK, ARRAYSIZE would be a better name but this is legacy code (no idea where it came from, it's at least 15 years old) so I pasted it 'as is'.

As been stated, the code actually work out the number of elements in an array, not struct. I would just write out the sizeof() division explicitly when I want it. If I were to make it a function, I would want to make it clear in its definition that it's expecting an array.
template<typename T,int SIZE>
inline size_t array_size(const T (&array)[SIZE])
{
return SIZE;
}
The above is similar to xtofl's, except it guards against passing a pointer to it (that says point to a dynamically allocated array) and getting the wrong answer by mistake.
EDIT: Simplified as per JohnMcG.
EDIT: inline.
Unfortunately, the above does not provide a compile time answer (even if the compiler does inline & optimize it to be a constant under the hood), so cannot be used as a compile time constant expression. i.e. It cannot be used as size to declare a static array. Under C++0x, this problem go away if one replaces the keyword inline by constexpr (constexpr is inline implicitly).
constexpr size_t array_size(const T (&array)[SIZE])
jwfearn's solution work for compile time, but involve having a typedef which effectively "saved" the array size in the declaration of a new name. The array size is then worked out by initialising a constant via that new name. In such case, one may as well simply save the array size into a constant from the start.
Martin York's posted solution also work under compile time, but involve using the non-standard typeof() operator. The work around to that is either wait for C++0x and use decltype (by which time one wouldn't actually need it for this problem as we'll have constexpr). Another alternative is to use Boost.Typeof, in which case we'll end up with
#include <boost/typeof/typeof.hpp>
template<typename T>
struct ArraySize
{
private: static T x;
public: enum { size = sizeof(T)/sizeof(*x)};
};
template<typename T>
struct ArraySize<T*> {};
and is used by writing
ArraySize<BOOST_TYPEOF(foo)>::size
where foo is the name of an array.

None has so far proposed a portable way to get the size of an array when you only have an instance of an array and not its type. (typeof and _countof is not portable so can't be used.)
I'd do it the following way:
template<int n>
struct char_array_wrapper{
char result[n];
};
template<typename T, int s>
char_array_wrapper<s> the_type_of_the_variable_is_not_an_array(const T (&array)[s]){
}
#define ARRAYSIZE_OF_VAR(v) sizeof(the_type_of_the_variable_is_not_an_array(v).result)
#include <iostream>
using namespace std;
int main(){
int foo[42];
int*bar;
cout<<ARRAYSIZE_OF_VAR(foo)<<endl;
// cout<<ARRAYSIZE_OF_VAR(bar)<<endl; fails
}
It works when only the value is around.
It is portable and only uses std-C++.
It fails with a descriptiv error message.
It does not evaluate the value. (I can't think up of a situation where this would be a problem because array type can't be returned by a function, but better be safe than sorry.)
It returns the size as compiletime constant.
I wrapped the construct into a macro to have some decent syntax. If you want to get rid of it your only option is to do the substitution manually.

KTC's solution is clean but it can't be used at compile-time and it is dependent on compiler optimization to prevent code-bloat and function call overhead.
One can calculate array size with a compile-time-only metafunction with zero runtime cost. BCS was on the right track but that solution is incorrect.
Here's my solution:
// asize.hpp
template < typename T >
struct asize; // no implementation for all types...
template < typename T, size_t N >
struct asize< T[N] > { // ...except arrays
static const size_t val = N;
};
template< size_t N >
struct count_type { char val[N]; };
template< typename T, size_t N >
count_type< N > count( const T (&)[N] ) {}
#define ASIZE( a ) ( sizeof( count( a ).val ) )
#define ASIZET( A ) ( asize< A >::val )
with test code (using Boost.StaticAssert to demonstrate compile-time-only usage):
// asize_test.cpp
#include <boost/static_assert.hpp>
#include "asize.hpp"
#define OLD_ASIZE( a ) ( sizeof( a ) / sizeof( *a ) )
typedef char C;
typedef struct { int i; double d; } S;
typedef C A[42];
typedef S B[42];
typedef C * PA;
typedef S * PB;
int main() {
A a; B b; PA pa; PB pb;
BOOST_STATIC_ASSERT( ASIZET( A ) == 42 );
BOOST_STATIC_ASSERT( ASIZET( B ) == 42 );
BOOST_STATIC_ASSERT( ASIZET( A ) == OLD_ASIZE( a ) );
BOOST_STATIC_ASSERT( ASIZET( B ) == OLD_ASIZE( b ) );
BOOST_STATIC_ASSERT( ASIZE( a ) == OLD_ASIZE( a ) );
BOOST_STATIC_ASSERT( ASIZE( b ) == OLD_ASIZE( b ) );
BOOST_STATIC_ASSERT( OLD_ASIZE( pa ) != 42 ); // logic error: pointer accepted
BOOST_STATIC_ASSERT( OLD_ASIZE( pb ) != 42 ); // logic error: pointer accepted
// BOOST_STATIC_ASSERT( ASIZE( pa ) != 42 ); // compile error: pointer rejected
// BOOST_STATIC_ASSERT( ASIZE( pb ) != 42 ); // compile error: pointer rejected
return 0;
}
This solution rejects non-array types at compile time so it will not get confused by pointers as the macro version does.

The macro has a very misleading name - the expression in the macro will return the number of elements in an array if an array's name is passed in as the macro parameter.
For other types you'll get something more or less meaningless if the type is a pointer or you'll get a syntax error.
Usually that macro is named something like NUM_ELEMENTS() or something to indicate its true usefulness. It's not possible to replace the macro with a function in C, but in C++ a template can be used.
The version I use is based on code in Microsoft's winnt.h header (please let me know if posting this snippet goes beyond fair use):
//
// Return the number of elements in a statically sized array.
// DWORD Buffer[100];
// RTL_NUMBER_OF(Buffer) == 100
// This is also popularly known as: NUMBER_OF, ARRSIZE, _countof, NELEM, etc.
//
#define RTL_NUMBER_OF_V1(A) (sizeof(A)/sizeof((A)[0]))
#if defined(__cplusplus) && \
!defined(MIDL_PASS) && \
!defined(RC_INVOKED) && \
!defined(_PREFAST_) && \
(_MSC_FULL_VER >= 13009466) && \
!defined(SORTPP_PASS)
//
// RtlpNumberOf is a function that takes a reference to an array of N Ts.
//
// typedef T array_of_T[N];
// typedef array_of_T &reference_to_array_of_T;
//
// RtlpNumberOf returns a pointer to an array of N chars.
// We could return a reference instead of a pointer but older compilers do not accept that.
//
// typedef char array_of_char[N];
// typedef array_of_char *pointer_to_array_of_char;
//
// sizeof(array_of_char) == N
// sizeof(*pointer_to_array_of_char) == N
//
// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T);
//
// We never even call RtlpNumberOf, we just take the size of dereferencing its return type.
// We do not even implement RtlpNumberOf, we just decare it.
//
// Attempts to pass pointers instead of arrays to this macro result in compile time errors.
// That is the point.
//
extern "C++" // templates cannot be declared to have 'C' linkage
template <typename T, size_t N>
char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N];
#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A)))
//
// This does not work with:
//
// void Foo()
// {
// struct { int x; } y[2];
// RTL_NUMBER_OF_V2(y); // illegal use of anonymous local type in template instantiation
// }
//
// You must instead do:
//
// struct Foo1 { int x; };
//
// void Foo()
// {
// Foo1 y[2];
// RTL_NUMBER_OF_V2(y); // ok
// }
//
// OR
//
// void Foo()
// {
// struct { int x; } y[2];
// RTL_NUMBER_OF_V1(y); // ok
// }
//
// OR
//
// void Foo()
// {
// struct { int x; } y[2];
// _ARRAYSIZE(y); // ok
// }
//
#else
#define RTL_NUMBER_OF_V2(A) RTL_NUMBER_OF_V1(A)
#endif
#ifdef ENABLE_RTL_NUMBER_OF_V2
#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V2(A)
#else
#define RTL_NUMBER_OF(A) RTL_NUMBER_OF_V1(A)
#endif
//
// ARRAYSIZE is more readable version of RTL_NUMBER_OF_V2, and uses
// it regardless of ENABLE_RTL_NUMBER_OF_V2
//
// _ARRAYSIZE is a version useful for anonymous types
//
#define ARRAYSIZE(A) RTL_NUMBER_OF_V2(A)
#define _ARRAYSIZE(A) RTL_NUMBER_OF_V1(A)
Also, Matthew Wilson's book "Imperfect C++" has a nice treatment of what's going on here (Section 14.3 - page 211-213 - Arrays and Pointers - dimensionof()).

Your macro is misnamed, it should be called ARRAYSIZE. It is used to determine the number of elements in an array whos size is fixed at compile time. Here's a way it can work:
char foo[ 128 ]; // In reality, you'd
have some constant or constant
expression as the array size.
for( unsigned i = 0; i < STRUCTSIZE(
foo ); ++i ) { }
It's kind of brittle to use, because you can make this mistake:
char* foo = new char[128];
for( unsigned i = 0; i < STRUCTSIZE(
foo ); ++i ) { }
You will now iterate for i = 0 to < 1 and tear your hair out.

The type of a template function is inferred automatically, in contrast with that of a template class. You can use it even simpler:
template< typename T > size_t structsize( const T& t ) {
return sizeof( t ) / sizeof( *t );
}
int ints[] = { 1,2,3 };
assert( structsize( ints ) == 3 );
But I do agree it doesn't work for structs: it works for arrays. So I would rather call it Arraysize :)

Simplfying #KTC's, since we have the size of the array in the template argument:
template<typename T, int SIZE>
int arraySize(const T(&arr)[SIZE])
{
return SIZE;
}
Disadvantage is you will have a copy of this in your binary for every Typename, Size combination.

function, no template function, yes
template, I think so (but C++
templates are not my thing)
Edit: From Doug's code
template <typename T>
uint32_t StructSize() // This might get inlined to a constant at compile time
{
return sizeof(T)/sizeof(*T);
}
// or to get it at compile time for shure
class StructSize<typename T>
{
enum { result = sizeof(T)/sizeof(*T) };
}
I've been told that the 2nd one doesn't work. OTOH something like it should be workable, I just don't use C++ enough to fix it.
A page on C++ (and D) templates for compile time stuff

I prefer the enum method suggested by [BCS](in Can this macro be converted to a function?)
This is because you can use it where the compiler is expecting a compile time constant. The current version of the language does not let you use functions results for compile time consts but I believe this coming in the next version of the compiler:
The problem with this method is that it does not generate a compile time error when used with a class that has overloaded the '*' operator (see code below for details).
Unfortunately the version supplied by 'BCS' does not quite compile as expected so here is my version:
#include <iterator>
#include <algorithm>
#include <iostream>
template<typename T>
struct StructSize
{
private: static T x;
public: enum { size = sizeof(T)/sizeof(*x)};
};
template<typename T>
struct StructSize<T*>
{
/* Can only guarantee 1 item (maybe we should even disallow this situation) */
//public: enum { size = 1};
};
struct X
{
int operator *();
};
int main(int argc,char* argv[])
{
int data[] = {1,2,3,4,5,6,7,8};
int copy[ StructSize<typeof(data)>::size];
std::copy(&data[0],&data[StructSize<typeof(data)>::size],&copy[0]);
std::copy(&copy[0],&copy[StructSize<typeof(copy)>::size],std::ostream_iterator<int>(std::cout,","));
/*
* For extra points we should make the following cause the compiler to generate an error message */
X bad1;
X bad2[StructSize<typeof(bad1)>::size];
}

I don't think that that really does work out the number of elements in a structure. If the structure is packed and you used things smaller than the pointer size (such as char on a 32-bit system) then your results are wrong. Also, if the struct contains a struct you are wrong too!

Yes it can be made a template in C++
template <typename T>
size_t getTypeSize()
{
return sizeof(T)/sizeof(*T);
}
to use:
struct JibbaJabba
{
int int1;
float f;
};
int main()
{
cout << "sizeof JibbaJabba is " << getTypeSize<JibbaJabba>() << std::endl;
return 0;
}
See BCS's post above or below about a cool way to do this with a class at compile time using some light template metaprogramming.

xtofl has the right answer for finding an array size. No macro or template should be necessary for finding the size of a struct, since sizeof() should do nicely.
I agree the preprocessor is evil, but there are occasions where it is the least evil of the alternatives.

As JohnMcG's answer, but
Disadvantage is you will have a copy of this in your binary for every Typename, Size combination.
That's why you'd make it an inline template function.

Answered in detail here:
Array Size determination Part 1
and here:
Array Size determination Part 2.

Windows specific:
There is the macro _countof() supplied by the CRT exactly for this purpose.
A link to the doc at MSDN

For C99-style variable-length arrays, it appears that the pure macro approach (sizeof(arr) / sizeof(arr[0])) is the only one that will work.

Related

Get size of an array-pointer template parameter

I wondered if I could auto deduce the size of an array, which is passed as a template parameter, without (explicitly) passing its size.
The following code both compiles warning-less on g++ 4.8 and clang++ 3.3 (using -std=c++11 -Wall).
#include <iostream>
template<const int* arr>
struct array_container
{
static constexpr int val = arr[1];
array_container() {
std::cout << val << std::endl;
}
// static constexpr int arr_size = ??;
};
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
// array_container<one> array_one;
array_container<two> array_two;
// (void) array_one;
(void) array_two;
return 0;
}
However, if I remove the two comment signs in main(), I get an out of bound error with both compilers.
Now, this is cool. Somehow the compiler knows the size of the array, though the type of const int* arr is a pointer. Is there any way to get the size of arr, e.g. to complete my comment in array_container?
Of course, you are not allowed to
Use any macros
Store the size in arr (e.g. passing an std::array as template parameter: constexpr std::array<int, 1> one = { 1 }, or using an end marker like '\0' in strings)
Use an additional template parameter for the size that can not be auto deduced (array_container<1, one> array_one).
Maybe std::extent template from <type_traits> header of C++11 standard library is what you want:
#include <iostream>
#include <type_traits>
constexpr int one[] = { 1 };
constexpr int two[] = { 1, 2 };
int main()
{
std::cout << std::extent<decltype(one)>::value << std::endl;
std::cout << std::extent<decltype(two)>::value << std::endl;
return 0;
}
Output:
1
2
template<size_t size>
constexpr size_t arraySize ( const int ( &arrayRef ) [size] ) {
return size;
}
int main(){
int A[1];
int B[2];
cout << arraySize(A) << arraySize(B);
return 0;
}
I believe something like this is what you're looking for, using array references. The syntax for declaring an array reference looks kind of like the syntax for a function pointer. This function template accepts an array reference named arrayRef, which prevents array-to-pointer decay so that compile-time info about array size is preserved. As you can see, the template argument is implicit to the compiler. Note that this can only work when the size can be deduced at compile time. Interestingly, this should still work without naming arrayRef at all. To make the above template more useful, you can add a template parameter to deduce the type of the array as well. I left it out for clarity.
Probably not, as SFINAE only happens in the immediate context, while that error comes from the requirement that UB in constexpr lead to a compile time error, which I think is not immediate. You could try a recursive SFINAE that stops on the UB, but even if it worked you would have to both check the standard and hope it does not change (as it is rather obscure and new).
The easy way is to ise s function to deduce the array size, have to explicitly pass it to the type, then store it in an auto. Probably not what you want.
There are proposals to allow type parameters to be deduced from value parameters, so you could wait for those instead.
Not a solid answer, more of an extended comment, so marked community wiki.
It is indeed possible. I found a solution using SFINAE. What it basically does is produce a substitution error if the index is out of bound (line 3 in this example):
template<class C>
static yes& sfinae(typename val_to_type<
decltype(*C::cont::data), *(C::cont::data + C::pos)>::type );
template<class C>
static no& sfinae(C );
The full source code is on github.
There are only two disadvantages:
You have to specify the type of the array (this can not be avoided)
It only works with g++ 4.8.1 and clang 3.3. g++ fails for empty strings (with a compiler bug). If someone can test for other compilers, that would be appreciated.

[C++ compile time assertions]: Can we throw a compilation error if some condition is not met?

I wrote a function:
template<int N> void tryHarder() {
for(int i = 0; i < N; i++) {
tryOnce();
}
}
but I only want it to compile if N is in between 0 and 10. Can I do it? How?
You can do it with static_assert declaration:
template<int N> void tryHarder() {
static_assert(N >= 0 && N <= 10, "N out of bounds!");
for(int i = 0; i < N; i++) {
tryOnce();
}
}
This feature is only avaliable since C++11. If you're stuck with C++03, take a look at Boost's static assert macro.
The whole idea of this are nice error messages. If you don't care for those, or can't even affor boost, you could do something as follows:
template<bool B>
struct assert_impl {
static const int value = 1;
};
template<>
struct assert_impl<false> {
static const int value = -1;
};
template<bool B>
struct assert {
// this will attempt to declare an array of negative
// size if template parameter evaluates to false
static char arr[assert_impl<B>::value];
};
template<int N>
void tryHarder()
{
assert< N <= 10 >();
}
int main()
{
tryHarder<5>(); // fine
tryHarder<15>(); // error, size of array is negative
}
For pre C++11 compilers, you could implement a template parameter constraint on the non-type parameter N.
For a description of how to do this, please see http://stroustrup.com/bs_faq2.html#constraints
Combined with the answers given so far already, the lower bound can be covered, too, by using unsigned int as template type. Negative values, if applied, will be converted to unsigned values high enough that they will be covered with the static_assert or the pre-C++11 solution anyway.
unsigned int additionally gives already semantically a hint that negative values shall not be applied to this template, which is why it (possibly) should be preferred in the specific case...
#if !defined(__cplusplus)
#error C++ compiler required.
#endif
This is just an example.
Here is the source link: http://msdn.microsoft.com/en-us/library/c8tk0xsk(v=vs.71).aspx
All i am saying is that you can use #error also
It is a directive
Edit #Pratik Chowdhruy: I agree with Paul R. This does not answer the question directly. Sorry to the community

What is sizeof(something) == 0?

I have a template that takes a struct with different values, for example:
struct Something
{
char str[10];
int value;
...
...
};
And inside the function I use the sizeof operator: jump in memory sizeof(Something);
Sometimes I would like to not jump anything at all; I want sizeof to return zero. If I put in an empty struct it will return 1; what can I put in the template to make sizeof return zero?
sizeof will never be zero. (Reason: sizeof (T) is the distance between elements in an array of type T[], and the elements are required to have unique addresses).
Maybe you can use templates to make a sizeof replacement, that normally uses sizeof but is specialized for one particular type to give zero.
e.g.
template <typename T>
struct jumpoffset_helper
{
enum { value = sizeof (T) };
};
template <>
struct jumpoffset_helper<Empty>
{
enum { value = 0 };
};
#define jumpoffset(T) (jumpoffset_helper<T>::value)
What do you think about it?
#include <iostream>
struct ZeroMemory {
int *a[0];
};
int main() {
std::cout << sizeof(ZeroMemory);
}
Yes, output is 0.
But this code is not standard C++.
No object in C++ may have a 0 size according to the C++ standard. Only base-class subobjects MAY have 0 size but then you can never call sizeof on those. What you want to achieve is inachievable :)
or, to put it mathematically, the equation
sizeof x == 0 has no object solution in C++ :)

What is a common C/C++ macro to determine the size of a structure member?

In C/C++, how do I determine the size of the member variable to a structure without needing to define a dummy variable of that structure type? Here's an example of how to do it wrong, but shows the intent:
typedef struct myStruct {
int x[10];
int y;
} myStruct_t;
const size_t sizeof_MyStruct_x = sizeof(myStruct_t.x); // error
For reference, this should be how to find the size of 'x' if you first define a dummy variable:
myStruct_t dummyStructVar;
const size_t sizeof_MyStruct_x = sizeof(dummyStructVar.x);
However, I'm hoping to avoid having to create a dummy variable just to get the size of 'x'. I think there's a clever way to recast 0 as a myStruct_t to help find the size of member variable 'x', but it's been long enough that I've forgotten the details, and can't seem to get a good Google search on this. Do you know?
Thanks!
In C++ (which is what the tags say), your "dummy variable" code can be replaced with:
sizeof myStruct_t().x;
No myStruct_t object will be created: the compiler only works out the static type of sizeof's operand, it doesn't execute the expression.
This works in C, and in C++ is better because it also works for classes without an accessible no-args constructor:
sizeof ((myStruct_t *)0)->x
I'm using following macro:
#include <iostream>
#define DIM_FIELD(struct_type, field) (sizeof( ((struct_type*)0)->field ))
int main()
{
struct ABC
{
int a;
char b;
double c;
};
std::cout << "ABC::a=" << DIM_FIELD(ABC, a)
<< " ABC::c=" << DIM_FIELD(ABC, c) << std::endl;
return 0;
}
Trick is treating 0 as pointer to your struct. This is resolved at compile time so it safe.
You can easily do
sizeof(myStruct().x)
As sizeof parameter is never executed, you'll not really create that object.
Any of these should work:
sizeof(myStruct_t().x;);
or
myStruct_t *tempPtr = NULL;
sizeof(tempPtr->x)
or
sizeof(((myStruct_t *)NULL)->x);
Because sizeof is evaluated at compile-time, not run-time, you won't have a problem dereferencing a NULL pointer.
In C++11, this can be done with sizeof(myStruct_t::x). C++11 also adds std::declval, which can be used for this (among other things):
#include <utility>
typedef struct myStruct {
int x[10];
int y;
} myStruct_t;
const std::size_t sizeof_MyStruct_x_normal = sizeof(myStruct_t::x);
const std::size_t sizeof_MyStruct_x_declval = sizeof(std::declval<myStruct_t>().x);
From my utility macros header:
#define FIELD_SIZE(type, field) (sizeof(((type *)0)->field))
invoked like so:
FIELD_SIZE(myStruct_t, x);

Compile time sizeof_array without using a macro

This is just something that has bothered me for the last couple of days, I don't think it's possible to solve but I've seen template magic before.
Here goes:
To get the number of elements in a standard C++ array I could use either a macro (1), or a typesafe inline function (2):
(1)
#define sizeof_array(ARRAY) (sizeof(ARRAY)/sizeof(ARRAY[0]))
(2)
template <typename T>
size_t sizeof_array(const T& ARRAY){
return (sizeof(ARRAY)/sizeof(ARRAY[0]));
}
As you can see, the first one has the problem of being a macro (for the moment I consider that a problem) and the other one has the problem of not being able to get the size of an array at compile time; ie I can't write:
enum ENUM{N=sizeof_array(ARRAY)};
or
BOOST_STATIC_ASSERT(sizeof_array(ARRAY)==10);// Assuming the size 10..
Does anyone know if this can be solved?
Update:
This question was created before constexpr was introduced. Nowadays you can simply use:
template <typename T>
constexpr auto sizeof_array(const T& iarray) {
return (sizeof(iarray) / sizeof(iarray[0]));
}
Try the following from here:
template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&array)[N] ))[N];
#define mycountof( array ) (sizeof( _ArraySizeHelper( array ) ))
int testarray[10];
enum { testsize = mycountof(testarray) };
void test() {
printf("The array count is: %d\n", testsize);
}
It should print out: "The array count is: 10"
In C++1x constexpr will get you that:
template <typename T, size_t N>
constexpr size_t countof(T(&)[N])
{
return N;
}
The best I can think of is this:
template <class T, std::size_t N>
char (&sizeof_array(T (&a)[N]))[N];
// As litb noted in comments, you need this overload to handle array rvalues
// correctly (e.g. when array is a member of a struct returned from function),
// since they won't bind to non-const reference in the overload above.
template <class T, std::size_t N>
char (&sizeof_array(const T (&a)[N]))[N];
which has to be used with another sizeof:
int main()
{
int a[10];
int n = sizeof(sizeof_array(a));
std::cout << n << std::endl;
}
[EDIT]
Come to think of it, I believe this is provably impossible to do in a single "function-like call" in C++03, apart from macros, and here's why.
On one hand, you will clearly need template parameter deduction to obtain size of array (either directly, or via sizeof as you do). However, template parameter deduction is only applicable to functions, and not to classes; i.e. you can have a template parameter R of type reference-to-array-of-N, where N is another template parameter, but you'll have to provide both R and N at the point of the call; if you want to deduce N from R, only a function call can do that.
On the other hand, the only way any expression involving a function call can be constant is when it's inside sizeof. Anything else (e.g. accessing a static or enum member on return value of function) still requires the function call to occur, which obviously means this won't be a constant expression.
It's not exactly what you're looking for, but it's close - a snippet from winnt.h which includes some explanation of what the #$%^ it's doing:
//
// RtlpNumberOf is a function that takes a reference to an array of N Ts.
//
// typedef T array_of_T[N];
// typedef array_of_T &reference_to_array_of_T;
//
// RtlpNumberOf returns a pointer to an array of N chars.
// We could return a reference instead of a pointer but older compilers do not accept that.
//
// typedef char array_of_char[N];
// typedef array_of_char *pointer_to_array_of_char;
//
// sizeof(array_of_char) == N
// sizeof(*pointer_to_array_of_char) == N
//
// pointer_to_array_of_char RtlpNumberOf(reference_to_array_of_T);
//
// We never even call RtlpNumberOf, we just take the size of dereferencing its return type.
// We do not even implement RtlpNumberOf, we just decare it.
//
// Attempts to pass pointers instead of arrays to this macro result in compile time errors.
// That is the point.
//
extern "C++" // templates cannot be declared to have 'C' linkage
template <typename T, size_t N>
char (*RtlpNumberOf( UNALIGNED T (&)[N] ))[N];
#define RTL_NUMBER_OF_V2(A) (sizeof(*RtlpNumberOf(A)))
The RTL_NUMBER_OF_V2() macro ends up being used in the more readable ARRAYSIZE() macro.
Matthew Wilson's "Imperfect C++" book also has a discussion of the techniques that are used here.
The Problem
I like Adisak's answer:
template <typename T, size_t N>
char ( &_ArraySizeHelper( T (&arr)[N] ))[N];
#define COUNTOF( arr ) (sizeof( _ArraySizeHelper( arr ) ))
It's what Microsoft uses for the _countof macro in VS2008, and it's got some nice features:
It operates at compile time
It's typesafe (i.e. it will generate a compile-time error if you give it a pointer, which arrays degrade too all too easily)
But as pointed out by Georg, this approach uses templates, so it's not guaranteed to work with local types for C++03:
void i_am_a_banana() {
struct { int i; } arr[10];
std::cout << COUNTOF(arr) << std::endl; // forbidden in C++03
}
Fortunately, we're not out luck.
The Solution
Ivan Johnson came up with a clever approach that wins on all accounts: it's typesafe, compile-time, and works with local types:
#define COUNTOF(arr) ( \
0 * sizeof(reinterpret_cast<const ::Bad_arg_to_COUNTOF*>(arr)) + \
0 * sizeof(::Bad_arg_to_COUNTOF::check_type((arr), &(arr))) + \
sizeof(arr) / sizeof((arr)[0]) )
struct Bad_arg_to_COUNTOF {
class Is_pointer; // incomplete
class Is_array {};
template <typename T>
static Is_pointer check_type(const T*, const T* const*);
static Is_array check_type(const void*, const void*);
};
For those who are interested, it works by inserting two "tests" before the standard sizeof-based array-size macro. Those tests don't impact the final calculation, but are designed to generate compile errors for non-array types:
The first test fails unless arr is integral, enum, pointer, or array. reinterpret_cast<const T*> should fail for any other types.
The second test fails for integral, enum, or pointer types.
Integral and enum types will fail because there's no version of check_type that they match, since check_type expects pointers.
Pointer types will fail because they'll match the templated version of check_type, but the return type (Is_pointer) for the templated check_type is incomplete, which will produce an error.
Array types will pass because taking the address of an array of type T
will give you T (*)[], aka a pointer-to-an-array, not a pointer-to-a-pointer. That means that the templated version of check_type won't match. Thanks to SFINAE, the compiler will move on to the non-templated version of check_type, which should accept any pair of pointers. Since the return type for the non-templated version is defined completely, no error will be produced. And since we're not dealing with templates now, local types work fine.
If you are on a Microsoft only platform, you can take advantage of the _countof macro. This is a non-standard extension which will return the count of elements within an array. It's advantage over most countof style macros is that it will cause a compilation error if it's used on a non-array type.
The following works just fine (VS 2008 RTM)
static int ARRAY[5];
enum ENUM{N=_countof(ARRAY)};
But once again, it's MS specific so this may not work for you.
You can't solve it in general, thats one the reasons for array wrappers like boost array (plus stl-style behaviour of course).
It appears not to be possible to obtain the sizeof array as a compile-time constant without a macro with current C++ standard (you need a function to deduce the array size, but function calls are not allowed where you need a compile-time constant). [Edit: But see Minaev's brilliant solution!]
However, your template version isn't typesafe either and suffers from the same problem as the macro: it also accepts pointers and notably arrays decayed to a pointer. When it accepts a pointer, the result of sizeof(T*) / sizeof(T) cannot be meaningful.
Better:
template <typename T, size_t N>
size_t sizeof_array(T (&)[N]){
return N;
}
Without C++0x, the closest I can get is:
#include <iostream>
template <typename T>
struct count_of_type
{
};
template <typename T, unsigned N>
struct count_of_type<T[N]>
{
enum { value = N };
};
template <typename T, unsigned N>
unsigned count_of ( const T (&) [N] )
{
return N;
};
int main ()
{
std::cout << count_of_type<int[20]>::value << std::endl;
std::cout << count_of_type<char[42]>::value << std::endl;
// std::cout << count_of_type<char*>::value << std::endl; // compile error
int foo[1234];
std::cout << count_of(foo) << std::endl;
const char* bar = "wibble";
// std::cout << count_of( bar ) << std::endl; // compile error
enum E1 { N = count_of_type<int[1234]>::value } ;
return 0;
}
which either gives you a function you can pass the variable to, or a template you can pass the type too. You can't use the function for a compile time constant, but most cases you know the type, even if only as template parameter.
Now STL libraries are available to decide/select array size compile time
#include <iostream>
#include <array>
template<class T>
void test(T t)
{
int a[std::tuple_size<T>::value]; // can be used at compile time
std::cout << std::tuple_size<T>::value << '\n';
}
int main()
{
std::array<float, 3> arr;
test(arr);
}
Output:
3