compile error: invalid use of non-static data member

I am stumped. Please help. What is invalid about this code?

class Row
{
    private:
    const int numSamples;
    int samples[numSamples];
    //int samples[2];  //this line compiles fine

    public:
    Row(const int ns): numSamples(ns) { }
};

Row row(2);

void setup()
{
}

void loop()
{
}

output:

Row:4: error: invalid use of non-static data member 'Row::numSamples' Row:5: error: from this location Row:5: error: array bound is not an integer constant

Got this error on Arduino 1.0.5-r2 and Arduino 1.0.6

Thank you.

Like it says, your element isn’t a compile time constant ( different to a variable simply marked const ).

Using consexpr in C++11 you can have a constant constructor, however not without messing with the IDE ( will be default hopefully in 1.5.8 ).

What you can use is a template, then your code boils down to an almost empty class:

template< unsigned N >
  class Row{
    private:
	int samples[ N ];
};

Row< 2 > row;

void setup()
{
}

void loop()
{
}

The constructor, nor the variable to hold the length is needed. You can add the constructor back in for other purposes.

Thank you pYro_65, that worked.

I don’t think C++11 is going to help. I compiled the following with MinGW.

/* this fails with:
	g++ Row.cpp
	g++ -Wall -std=c++11 Row.cpp
*/
class Row
{
    private:
	const int numSamples;	//error: invalid use of non-static data member 'Row::numSamples'
	int samples[numSamples]; //error: array bound is not an integer constant

    public:
	Row(const int ns): numSamples(ns) { }
};

Row row(2);

int main()
{
}
/* this compiles */
template< unsigned N >
  class Row{
    private:
	int samples[ N ];
};

Row< 2 > row;

int main()
{
}

Yeah, not like you have it, your code will have to change. Constexpr will allow you to use return values / parameters as compile time constants. However your constructor has nothing to do with the line of code that sizes the array.

As the input is constant, there may be no need for a class as you can do quite a bit using constexpr functions. However if the storage is required ( can't act on data as it happens ) then there is not much you can do unless you want to start using dynamic memory.

pYro_65, constexpr looks interesting. How to make constexpr compile in this example?:

class Row
{
    private:
    constexpr int numSamples;//error: non-static data member 'numSamples' declared 'constexpr'
    int samples[numSamples]; //error: invalid use of non-static data member 'Row::numSamples'

    public:
    Row(const int ns): numSamples(ns) { }
};

Row row(2);

int main()
{
}

Output:

C:\demo_MinGW>g++ -Wall -std=c++11 Row.cpp Row.cpp:23:16: error: non-static data member 'numSamples' declared 'constexpr' constexpr int numSamples; ^ Row.cpp:23:16: error: invalid use of non-static data member 'Row::numSamples' Row.cpp:24:14: error: from this location int samples[numSamples]; ^

If you are going to create variable sized objects, why not just dynamically allocate the array?

Hi PaulS.
The Row class will be in a library. Row will be used by various .ino programs.
The size of the sample array is a constant value determined by the .ino program.

This example shows Row with two elements in the samples array:

#include <iostream>

template< unsigned N >			//number of samples
class Row{
	private:
		int samples[ N ];	//array of samples
	public:
		void scan()
		{
			for (int i=0; i<N; i++)
			{
				samples[i] = i;
				std::cout << samples[i];
			}
		}
};

const int N=2;
Row< N > row;

int main()
{
	row.scan();
}

I’m not sure how that is an improvement over:

class Row{
	private:
		int *samples;	//array of samples
                unsigned int sampleCount;
	public:
                Row(unsigned int N)
                {
                    sampleCount = N;
                    samples = new int[sampleCount];
                }

                ~Row()
                {
                   if(samples)
                     delete samples;
                }
                 
		void scan()
		{
			for (int i=0; i<N; i++)
			{
				samples[i] = i;
				std::cout << samples[i];
			}
		}
};

Thank you for your response PaulS.

The number of samples is a constant known at compile time. So using template to set array size avoids the overhead of dynamically allocate the array. Sorry I did not give good answer to your first question before. The life of Row objects is until end of program, so ~Row destructor is not needed.

The life of Row objects is until end of program, so ~Row destructor is not needed.

It's always a good idea to provide one, anyway.

PaulS:

The life of Row objects is until end of program, so ~Row destructor is not needed.

It's always a good idea to provide one, anyway.

but its not to use 'this->' huh.

Deconstructors are generated implicitly by the compiler when missing. What's going to be inside it?

What's going to be inside it?

Possibly nothing. But, the presence of one means that the class author though about the need to clean up resources when the instance ends.