Advertisement

Matrices & templates - an unholy union?

Started by July 15, 2000 03:20 PM
3 comments, last by null_pointer 24 years, 5 months ago
heh heh I'm learning matrix math and so I'm trying to build a matrix class in C++. It's templated. *groans* Anyway, the idea is simple: provide one matrix class that can use any type for its elements, with any number of rows and columns. It's the implementation that's stumping me. There are two rules that I'm having trouble with - matrix addition and matrix multiplication. 1. (addition) the matrices are of the same dimensions 2. (multiplication) the inner dimensions of the matrices must be equal (as in: 2x3 * 3x4) I can't use templated member functions, so I'll have to use global operators (which is better anyway). Here is my basic matrix class definition:

template &lttypename element_type, unsigned int rows = 4, unsigned int columns = 4>
	class matrix
{
public:
	element_type array[rows][columns];
};
  
Not too shabby, eh? Well, check out the operators:

template &lttypename element_type, unsigned int rows, unsigned int columns>
	matrix&ltelement_type, rows, columns> operator +(matrix&ltelement_type, rows, columns>& first, matrix&ltelement_type, rows, columns>& second)
{
	matrix&ltelement_type, rows, columns> result;

	for( unsigned int x=0; x < rows; x++ )
		for( unsigned int y=0; y < columns; y++ )
			result[x][y] = first[x][y] + second[x][y];

	return( result );
}


template &lttypename element_type, unsigned int rows, unsigned int columns>
	matrix&ltelement_type, rows, columns> operator -(matrix&ltelement_type, rows, columns>& first, matrix&ltelement_type, rows, columns>& second)
{
	matrix&ltelement_type, rows, columns> result;

	for( unsigned int x=0; x < rows; x++ )
		for( unsigned int y=0; y < columns; y++ )
			result[x][y] = first[x][y] - second[x][y];

	return( result );
}


template &lttypename element_type, unsigned int first_outer_dimension, unsigned int inner_dimension, unsigned int second_outer_dimension>
	matrix&ltelement_type, first_outer_dimension, second_outer_dimension> operator *(matrix&ltelement_type, first_outer_dimension, inner_dimension>& first, matrix&ltelement_type, inner_dimension, second_outer_dimension>& second)
{
	matrix&ltelement_type, first_outer_dimension, second_outer_dimension> result;

	for( unsigned int x=0; x < rows; x++ )
	{
		for( unsigned int y=0; y < columns; y++ )
		{
			element_type sum = 0;

			for( unsigned int index=0; index < columns; index++ )
			{
				sum += first[x][index] * second[index][y];
			}

			result[x][y] = sum;
		}
	}

	return( result );
}
  
Now, when I try to do matrix addition and matrix multiplication according to those two rules I listed earlier, I get errors. With addition, the compiler just crashes with an Internal (actually, it should be Infernal) Compiler Error thingy. With multiplication, the compiler complains that it can't resolve the parameter: "second_outer_dimension." Here's the error for multiplication:
quote: MSVC Compiler Error C:\Program Files\Microsoft Visual Studio\MyProjects\Temp22\Temp22.cpp(130) : error C2783: 'class matrix&ltelement_type,first_outer_dimension,inner_dimension> __cdecl operator *(class matrix&ltelement_type,first_outer_dimension,inner_dimension> &,class m atrix&ltelement_type,first_outer_dimension,inner_dimension> &)' : could not deduce template argument for 'second_outer_dimension'
Oh yeah, please don't worry about optimization until I understand how this thing works... Thanks! - null_pointer Sabre Multimedia (edited to re-format template brackets) Edited by - null_pointer on 7/15/00 3:28:30 PM
I just tried your code with MSVC 6 SP4, operator+ and operator- compiled fine (I didn''t run the program, just tried compiling it). As for operator* I couldn''t figure out why that wasn''t working, but if you don''t mind them both needing to be the same size you change it slightly to:

template class matrix{public:	typedef element_type elm_type;	enum{row_count = rows};	enum{col_count = columns};		element_type array[rows][columns];}; 


and operator* to

template T operator *(T& first, T& second){	T result;		for( unsigned int x=0; x < T::row_count; x++ )	{		for( unsigned int y=0; y < T::col_count; y++ )		{			typename T::elm_type sum = 0;						for( unsigned int index=0; index < T::col_count; index++ )			{				sum += first.array[x][index] * second.array[index][y];			}						result.array[x][y] = sum;		}	}		return(result);} 


Not really a very good solution though, maybe somebody else has a better idea.

quote:
Oh yeah, please don''t worry about optimization until I understand how this thing works...


I was more worried about the non-const parameters for the operators
Advertisement
I just wrote a small template matrix-vector library myself, so I think I know the answer to your question: tough luck. MSVC, through v6.0 w/ SP4, will not properly deduce a general matrix multiplication. Obviously, it has no knowledge of the matrix as such, but I''ve not had the compiler''s deduction fail before. I''ve had it fail on 3 or 4 different template signatures for different matrix multiplies ( the general case [ RxC = RxN * NxC ], square case [ NxN = NxN * NxN], and some other weird attempts). There''s just something about the formulation VC chokes hard on.

I resorted to creating operators only for those versions I really need. It sucks hard, but I have no other real choice for PC work than MSVC. Hopefully v7.0 will have some half-decent template support. Until then, it''s soap-on-a-rope.
Actually, the code as it stands above will only compile if you never attempt to add, subtract, or multiply any vectors (I did the same thing at first). Once you add a main which does anything, you''ll get compile errors. However with VC 6 SP3, I actually get descriptive errors for the + and - operators, so I see the problem -- it''s the line
result[x][y] = first[x][y] + second[x][y]; 

Which attemps to use [] on objects of matrix type. Obviously, this is a problem. You either have to do
result.array[x][y] = first.array[x][y] + second.array[x][y]; 

(Which is just not very cool) or add an operator[] to your array class:
inline element_type* operator[](int nRow) { return array[nRow]; } 


However, I was NOT able to solve your operator* problem. I get the same error about "second_outer_dimension", but I don''t know why.

Hope this helps.
...Syzygy
Thanks everyone! I kinda figured it was VC''s template support...

I didn''t include part of the matrix class definition, which is:

public:	element_type* operator[](unsigned int index) { return( &array[index][0] ); } 



That operator allows the matrix type to be used as a multi-dimensional array.

Can anyone try to compile and test the code with the latest Borland command line compiler?



- null_pointer
Sabre Multimedia

This topic is closed to new replies.

Advertisement