Passing matrices into classes

Hello guys,
I am currently trying to pass a matrix (multidimensional array) from my main into a function in a class. As usual, you have to include all array sizes, except the first. Unfortunately, the size saved under a variable. When I write it in the square brackets, it doesn't work.
Example:

1
2
3
4
5
6
7
8
9
10
//main
int main ()
{
int n = 5;
random object;
object.declare_variable(n);

int array [3][n];
object.pass_matrix(array);
}



1
2
3
4
5
//header
public: void declare_variable(int);
        void pass_matrix (int [][var]);

private: int var;


1
2
3
4
5
6
7
8
9
10
//class
void random::declare_variable(int x)
{
     var = x;
}

void random::pass_matrix (int matrix[][var])
{
...
}




I also tried, putting the variable 'var' in the public section above the void and declaring it as static, but still there are error messages; fewer, in my case:

...not an integer constant




So what should I do? Id like to repeat that the int n will vary, which is why I can't just directly write down the size.
C++ templates to the rescue!

http://www.cplusplus.com/forum/general/49079/

Take a look through the whole thread to see your options. If that is overload for you, the simplest is really just to template it:

1
2
3
4
5
6
7
8
9
10
11
12
template <typename T, size_t N, size_t M>
void print( T (&xs)[ N ][ M ] )
  {
  for (size_t n = 0; n < N; n++)
    {
    for (size_t m = 0; m < M; m++)
      {
      cout << xs[ n ][ m ] << " ";
      }
    cout << endl;
    }
  }

Hope this helps.
Whoa cool.
Thanks a lot, for this quick, short and precise answer Duoas!
It works fine now.
Just one question left: What about these
throw 
and
new[]
operators? I tried to find out how do it myself before, and only found examples with these operators, that I did not understand.
This (with the templates) is so much easier somehow.
The new and delete operators are for managing dynamically allocated memory.
http://www.cplusplus.com/doc/tutorial/dynamic/

The throw statement raises an exception -- a fancy way of saying "aargh something horrible happened".
http://www.cplusplus.com/doc/tutorial/exceptions/

Hope this helps.
Ok. I know used the templates on my main program I am working on, but it didn't work. After quite a few experiments, I found out what the problem is: During the course of the program, these non-constant integers have been made. But by using templates, you somehow have to pass through constant types. So I tried to make a new constant integer but somehow that also didn't work.

How can you make a not-constant integer constant, so that you can use this template function?

Examples:

This integer can not be passed through a template:

int a = 7


This one also can't be passed through:

int a = 7;
const int b = a;


Meanwhile, this would work:
const int a = 7;
Template metaprogramming is tricky because you have to keep track of two layers of abstraction.

The usual layer: code you write gets compiled and stored for later execution.
Template stuff: you're programming the compiler

For example, you may want to average two numbers. You write a function:

1
2
3
4
double average( double a, double b )
  {
  return (a + b) / 2;
  }

It works great. But then you go and write code using complex numbers. You have to rewrite the function:

1
2
3
4
std::complex <double> average( std::complex <double> a, std::complex <double> b )
  {
  return (a + b) / 2;
  }

Oh, then you have some calculations that need to take advantage of the increased precision your compiler (may) give you if you use long doubles. More rewrites:

1
2
3
4
5
6
7
8
9
long double average( long double a, long double b )
  {
  return (a + b) / 2;
  }

std::complex <long double> average( std::complex <long double> a, std::complex <long double> b )
  {
  return (a + b) / 2;
  }


As you can see, we are still only writing normal, gets compiled, stored, and executed later stuff. But it is a lot of stuff just to do one thing:

    return (a + b) / 2;

(That one thing need not be so simple. It could be very complex, which makes the rewriting even more obnoxious.) All this leads to duplicate code that is hard to maintain.


What if we could tell the compiler to do it for us?

Yes, that is the purpose of templates. We create a cookie-cutter template for something for the compiler, so when we need a function that does that thing to a double or an int, we just use it and the compiler writes and compiles the code for us.

1
2
3
4
5
template <typename T>
T average( T a, T b )
  {
  return (a + b) / 2;
  }


Now to your question. The important point of all this template stuff is that everything must be resolved before your program gets executed.

This makes sense. You cannot create and compile code on-the-fly while your program is running, since the compiler is not running as part of your program.

Which means that things like int a = 7; cannot be used to resolve template functions, because a is a variable — your program can change it at any time. But your program cannot change what has been compiled to match it.


In short, you need to change the structure of your program to not rely on runtime values. Make whatever you are trying to change into an argument to the function.

Hope this helps.
Thanks for that answer. The problem is just the following:

1. My program loads texts through the ifstream. That means, if you change the text, the integer also changes.
Now, I haven't tried to load texts into a constant array, and I really doubt it would work.

There is also a second reason:
2. The program reads the text and if certain things apply, certain functions should be called up. I first started to write the whole program into my main, but then reallised that it really started to get messed up. So I started to write it into a class, not only to practise the use of classes.
The strings and arrays I create in the main are changed through functions in classes. Until now, there was no problem. Now, the program includes a matrix. As the passing of the multi-dimensional didn't work, I posted this question.
I haven't tried to find a way not to use matrices yet, beacause I didn't expect that it is very difficult.

So is there really no other way?

PS.: Thanks again for your quick answers. They are very clear and easy to understand!!
What you are asking to happen is to have your program
1) read a text file
2) change its compiled code to match

That doesn't work. Your program cannot change itself like that.

You still haven't given a clear statement of your problem. If I gather correctly, you have a class something like:

1
2
3
4
5
template <typename T, int Rows, int Cols>
struct matrix
  {
  ...
  };

And you want to read a variable-dimensioned matrix from file into a class like that?

Here's the rub. That's the wrong way.

While it does provide nice compile-time checks that you aren't passing a 3x4 matrix to a function that expects a 4x3 matrix, the utility of such a check is a little overrated. It would be nice if it were usable! But it isn't.

Change the Rows and Cols to arguments to your matrix constructor. Then, perform a check whenever you try to use two matrices that they are compatible. This only takes a couple of cycles and is not a limiting factor. Beyond that, almost all your code remains the same.

There are two basic ways to respond to mismatches:
1) throw an exception
2) return an invalid matrix (say, a 0x0 matrix). When the user realizes he's getting garbage out, he can hunt down the error.

1
2
3
4
5
6
7
8
9
10
template <typename T>
struct matrix
  {
  const int rows;
  const int cols;

  matrix( int rows, int cols ): rows( rows ), cols( cols ) { ... }

  ...
  };

Hope this helps.
I think that templates with way overkill for this dude,

xantavis, if you never seen what a two dimensional array looks like in memory this might be hard for you to understand, (by seen I mean drawn on board :).

what you want is a dynamically allocated two dimensional array, sounds scary, but its not, its lesson three in programming course.

instead of trying this
int array[3][n]
which should not pass through compilation, since the compiler has no idea what size the pointer arithmetic should be,

try this
1
2
3
int ** array = new (int*)[3];
for(int i=0; i<3; ++i)
   array[i] = new int[n];


this should work out fine and create a two dimensional array,

to pass this to a function just pass the "array" like so
foo( array ); that simple

catching is a bit trickier, this would be the declaration for foo
1
2
3
4
5
return_value foo(int ** array){

   //array[x][y] = bla bla code;

}


and you probably want to pass in the sized of the two dimensional array, or matrix, whatever.

templates is lesson 10 in programming course number 2, way overkill for something as simple as passing matrix to a function.
Topic archived. No new replies allowed.