define type (struct) inside of class as public so that user can use it.

hi community,

my class uses the MultiMap function to calculate some values.
my idea was to define a 'new datatype' for the multimap.
that means a struct with 'size' filed and 'in' and 'out' arrays
i wanted to make this only available through the class.
so i defined this struct in the public area of the class definition:

// Class Definition:
class slight_Test {
	public:
		// public typedefs:
			
			// variant 1
			typedef struct {
				byte size = 4;
				word mm_In[4];
				word mm_Out[4];
			} tmultimap;
			
			// variant 2			
			// struct sMultiMap {
				// static const byte size;
				// word mm_In[size];
				// word mm_Out[size];
			// };
			// typedef struct sMultiMap tmultimap; 
....

there are two variants.
both generates some errors if try to compile them and have used this type this way in my sketch:

slight_Test::tmultimap tmultimapMyTestMap = {
	4,
	{     0,   100,  1000, 65535},
	{     0,     1,   200,   255}
};

variant 1 errors:

slight_Test_LibDev.ino: At global scope:
slight_Test_LibDev.ino:111: warning: missing braces around initializer for 'word [4]'
slight_Test_LibDev:111: error: braces around scalar initializer for type 'word'

if i uncomment the other version (variant 2) i get this errors:

In file included from slight_Test_LibDev.ino:104:
C:\...\arduino_sketchbook\libraries\slight_Test/slight_Test.h: At global scope:
C:\...\arduino_sketchbook\libraries\slight_Test/slight_Test.h:61: error: array bound is not an integer constant
C:\...\arduino_sketchbook\libraries\slight_Test/slight_Test.h:62: error: array bound is not an integer constant

i do not understand this error - size is defined as static and const ?! what other way to go?

variant2 is the think i really want to do.
is this the right way?
i think i could do something like this with an class definition and malloc in the constructor as i found in Pass array size to class constructor
but is it possible to declare a class in an class??
so is there a 'easy' way to do this just with structs or is there a other way?

i added an zip file with the test library / test class.
i also added the files separated so you just can open it for a short look without unpacking the zip.
this class does nothing useful..
its just for testing concepts..

i hope there is someone that can help me to learn some more about c++ concepts and how to do such things :wink:

sunny greetings
stefan

slight_Test.zip (11.1 KB)

slight_Test.h (4.75 KB)

slight_Test.cpp (10.1 KB)

slight_Test_LibDev.ino (23.9 KB)

Defining a type and defining an instance of that type are two separate steps. Do NOT try to do them in one step. The struct definition belongs OUTSIDE of the class. The instance of the struct belongs IN the class.

You can't make the arrays run-time sizable without using malloc() or new.

It is fine to put object declarations inside other objects, and using templates you can solve the problem of arbitrary sized structs. Refrain from using typedefs on structs, in C++ unless you modify the type provided in someway using the typedef, it is completely pointless and does nothing.

Below is one possible solution. There is a function in the top-level class showing how to use the different sized objects. Also using a template means we no longer need to store the size, it is part of the types definition.

Of course there may be a bit of a learning curve for you here, but I made it as straight forward as I could. This is a working example.

class Foo{
  public:
  
    template< unsigned N >
      struct Obj{
        enum{ Size = N };
        word mm_In[ Size ];
        word mm_Out[ Size ];
    };
    
    template< unsigned N >
      void DoStuff( Obj< N > &o ){
        
        Serial.println( o.Size );
        return; 
      }
  protected:
  private:
};

Foo::Obj< 4 > obj = {
	{ 0, 100, 1000, 65535 },
	{ 0, 1, 200, 255}
};

Foo::Obj< 8 > obj_big = {
	{ 1, 2, 3, 4, 5, 6, 7, 8 },
	{ 1, 2, 3, 4, 5, 6, 7, 8 }
};

void setup() {
  
  Foo f;
  
  Serial.begin( 9600 );
  f.DoStuff( obj );
  f.DoStuff( obj_big );
}

void loop(){}

Hi all,

thanks pYro_65 for the thing with the templates. the example is easy to understand as starting point - i will read some more about it..
for my current problem i have the feeling that the concept of templates are to 'heavy' / complicated.. eventually i want to use the struct also in the main code..

@PaulS i know that i cant make a run-time sizable array without malloc.
i only want to have a fixed sized array.
my idea was to have a struct so the things that belong together are written in one 'thing'
i also have no problem to move the struct definition out of my class. i only need this type for this class - so i tried to move it to local point as possible.

i try to explain / outline the idea i wish to achieve with some code examples:
struct

// that example does not work....
typedef struct {
	static const byte size;
	word mm_In[];
	word mm_Out[];
} tmultimap;

and using it like this:

tmultimap tmultimapMyTestMap = {
	4,
	{     0,   100,  1000, 65535},
	{     0,     1,   200,   255}
};

tmultimap tmultimapMyTestMap2 = {
	3,
	{     0,   100,   100},
	{     0,     0,   200}
};

i hope i it is clear enough?!

as workaround i will use a fixed array size until i find a solution that fits in :wink:
so i have a 'maximal size'.

// some other thing:
is it possible to include libraries (*.h files) after some other code?
or should i include it at the first place in the main sketch?
at the moment i try to pack things logical - so i include my lib and than have the variables for this part. than comes the next include with the corresponding variables and so on..
(i had some unexpected behavior in my last test.. and moving the include to the top of the file fixed it..)

sunny greetings
stefan

typedef struct {
	static const byte size;
	word mm_In[];
	word mm_Out[];
} tmultimap;

You know, by now, that you can not just declare something to be an array without giving it a size. Since you don't know what absolute size to use, your ONLY choice is dynamic allocation once you know the size.

But, feel free to keep beating your head against the wall. It's not hurting me or the wall.

Your declarations are invalid, you cannot initialize a static member in an initializer list.
I think you may have misunderstood the implication of static in reference to objects.

A static member is intialized one time only and is not unique to instances of the class. Static members are "class members", not "object members", or can be seen as singular rather than per-instance.

Why not have a function in a class that takes two pointers and a length? Then you can simply pass stack based arrays when needed avoiding dynamic memory.

I've been playing with a similar structure for polygons. You could try:

typedef struct tmultimap{
	const byte	size;
	const word *	mm_In;
	const word *	mm_Out;
};

static const word wrdMyTestMapIn[]	= { 0,	100,	1000,	65535 };
static const word wrdMyTestMapOut[]	= { 0,	  1,	 200,	  255 };
static tmultimap tmultimapMyTestMap	= { 4, wrdMyTestMapIn, wrdMyTestMapOut };

@pYro_65: thanks for the tip with 'static' - i have read throu some documentation now - you are right - i did not know what static really did.. :wink:

@andrewzuku: thanks for the tip to use pointers and declare the arrays outside of the struct!

now i think there are 'all' possible solutions in this thread:

  • Templates
  • Pointers
  • Dynamic allocation (maloc)
  • fixed array size

one idea for the pointer thing came to my mind: is it possible to declare on element of an struct as const
and initialize it in initialiser list? like this?

struct testThing {
	const byte sizeX;
	word *mm_In;
	word *mm_Out;
};

testThing ttNewTest					= {4, wNewTest_In, wNewTest_Out};	// line 1
word wNewTest_In[ttNewTest.sizeX]	= { 0, 100, 1000, 65535 };			// line 2
word wNewTest_Out[ttNewTest.sizeX]	= { 0,   1,  200,   255 };			// line 3
// this gererates some errors:
// line 1: error: 'wNewTest_In' was not declared in this scope
// line 1: error: 'wNewTest_Out' was not declared in this scope
// line 2: error: array bound is not an integer constant
// line 3: error: array bound is not an integer constant

// that works.
const byte cbSize = 4;
word wNewTest2_In[cbSize]	= { 0, 100, 1000, 65535 };
word wNewTest2_Out[cbSize]	= { 0,   1,  200,   255 };
testThing ttNewTest2			= {cbSize, wNewTest2_In, wNewTest2_Out};

the first error is clear- the thing is not declared at this point.
i think there is a way to get around this but i dont remember..
i dont understand the second error - the member 'sizeX' is const - so why does the compiler dont like this?

just for my understanding:
when do i need the 'typedef' variant and when is it fine with just 'struct' ??

for me one important point is to write some easy to read and understand code.
(at least for me to easy understand it :wink: )
with an initializer list on an struct i have a clean block what belongs to one 'thing'
so you can 'catch' it while scrolling through the code...
with the pointers you have some 'ugly' extra variables... :wink:
it is just a personal taste.
in my current project i solved it with the 'fixed array size' way - i just set an 'maximal' allowed array size.
(its not the finest thing to have some unused empty memory blocked -
but hey its just one or two word values - if i run out of memory i know where to cut down usage..)
sunny greetings stefan

when do i need the 'typedef' variant and when is it fine with just 'struct' ??

Never!, not for declaring structs anyway. Class/structs/unions have no requirement for typedef, it is not needed. ( C hippies may have something to say, but hey, we shouldn't care about them too much, Arduino uses a C++ compiler. )

i dont understand the second error - the member 'sizeX' is const - so why does the compiler dont like this?

The struct that contains it isn't, though. And, even if it were, how do you propose to later assign sizeX a value? Because it is const, relative to the struct anyway, the ONLY time that you can assign a value to it is when it is declared.