A function to get the number of variables in an array?

Creating a static array, while requiring a static for initialisation is just plain ridiculous, how about just typing the number Nick?. The template is not for nonsensical reasons obviously.

And just in case there is a strong aversion to remembering the number, here is a compile time version, which is still safer than the macros provided.

template< typename T > struct ArraySize;
template< typename T, size_t N > struct ArraySize< T[N] >{ enum{ Size = N }; }; 

Serial.println( ArraySize< typeof( ledPins ) >::Size );

pYro_65:
Creating a static array, while requiring a static for initialisation is just plain ridiculous, how about just typing the number Nick?. The template is not for nonsensical reasons obviously.

I don't think it's ridiculous. Suppose I wanted to define an array of pin numbers, and an array of state data associated with the pins - I'd want the second array to be the same size as the first one without having to hard-code the size of either array.

The big advantage for me of the macros versus the templates is that I can glance at the macro and see immediately what it does, while I stare at those templates and think WTF is going on here?

pYro_65:
And just in case there is a strong aversion to remembering the number, here is a compile time version, which is still safer than the macros provided.

The template-Fu is strong in this one. :wink:

PeterH:

pYro_65:
Creating a static array, while requiring a static for initialisation is just plain ridiculous, how about just typing the number Nick?. The template is not for nonsensical reasons obviously.

I don't think it's ridiculous. Suppose I wanted to define an array of pin numbers, and an array of state data associated with the pins - I'd want the second array to be the same size as the first one without having to hard-code the size of either array.

This is a mildly flawed approach in C++ ( not so much C ), considering structs will remove the data separation and provide encapsulation, and a hard coded value provides safety against silly mistakes. The defines are not specifically for an array, so it will happily compile broken code.

while I stare at those templates and think WTF is going on here?

Something new to learn maybe??
C++ provides these type-safe mechanisms because of the short falling's encountered in C. Using unsafe practices because they are 'easier', in my opinion is not the best way to develop software.

... all to fit data in a few kb of stack space?

With the large numbers of beginners on this forum, the simpler structures/concepts are far more effective than complexity. Relatively advanced topics are, imho, not for people that often struggle to make 2 LEDs blink (as interesting as the discussion may be for subject matter experts).

I have been programming Arduino for about a year now. I have a background in real time programming under Unix, Windows, and VMS, using C mostly. In my experience, the fewer layers between hardware and software, the more understandable things are and the more reliable the (real-time) result.

An opinion. :wink:

So we could add in a define to make it more readable?

template< typename T > struct ArraySize;
template< typename T, size_t N > struct ArraySize< T[N] >{ enum{ Size = N }; }; 

#define NUMITEMS(arg) ArraySize< typeof( arg ) >::Size

int foo [] = { 5, 6, 7, 8, 9 };
int bar [ NUMITEMS (foo) ];   // make another array the same size

void setup ()
  {
  Serial.begin (115200);
  Serial.println( NUMITEMS (foo) );
  Serial.println( NUMITEMS (foo) );
  Serial.println (sizeof (ArraySize< typeof( bar ) >));
  }  // end of setup

void loop () { }

And tell me, why does the struct have a size of 1? This is the code output:

5
5
1

And tell me, why does the struct have a size of 1?

Because you took the sizeof the ArraySize struct. Not something passed to it.

http://stackoverflow.com/a/2362117:
The standard does not allow objects (and classes thereof) of size 0, since that would make it possible for two distinct objects to have the same memory address. That's why even empty classes must have a size of (at least) 1.

Hence:

struct Empty{};
struct Full{char a;}

Will be the same if the sizeof is taken.

Seeing as you do not create an instance of the object, you do not pay the price, it is a global interface.

pYro_65:
Because you took the sizeof the ArraySize struct. Not something passed to it.

I didn't expect it to be 10, I thought it might be zero. But your explanation makes sense.

pYro_65:
Something new to learn maybe??
C++ provides these type-safe mechanisms because of the short falling's encountered in C. Using unsafe practices because they are 'easier', in my opinion is not the best way to develop software.

I have used templates occasionally and can generally follow what they're doing but I rarely code in C++ and have not got comfortable with them. Definitely on the list of things that still need to be properly learned - but it's a long list and this is nowhere near the top.

The problem (as I see it) with the OO and templated approach is that it introduces quite a big step in the learning curve. I would happily use an OO approach for my own code, but faced with a newcomer who isn't entirely sure what an array is or what 'const' means, I wouldn't be doing them any favors by recommending that they use classes and templates to solve their problem. Just declaring a const array of pin numbers and a corresponding array of variables of the right size solves their problem without any significant short fallings. Heck, just persuading people to use arrays in the first place rather than pin, pin2 and so on can be an uphill struggle.

The problem (as I see it) with the OO and templated approach is that it introduces quite a big step in the learning curve.

Not as long as you have a 22 foot inseam. 8)