How can I implement templates here?

Mar 24, 2017 at 8:50pm
Hello guys, I am currently working on an assignment that is due in 3 days. The program is supposed to make two matrices to perform arithmetic on them. I have managed to solve the whole thing (addition, subtraction and multiplication). The professor said that we should try to add templates to see how they work. To my understanding a template is a generic data type, but I have never implemented it before. Currently my program deals with matrices that have elements inside them of type (int). I want to make it so if the user inputs a double or a float in an element the program is still able to process the matrix operation. The function that sets the matrix elements is "setMatrix()" I suppose that something has to be done there. I just have no idea what to do :(. Any comments/hints/suggestions are greatly appreciated. Code below:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
Matrix.h

#pragma once
#include "iostream"

using namespace std;

const int maxRows = 6;
const int maxColumns = 6;

class Matrix
{

public:

	int rows, columns, a[maxRows][maxColumns];

public:
	Matrix(int, int);

	friend ostream& operator<<(ostream& os, const Matrix& m);

	void setMatrix();
	
	Matrix operator+(const Matrix& m);
	Matrix operator-(const Matrix& m);
	Matrix operator*(const Matrix& s);
};

Matrix.cpp
#include "Matrix.h"

Matrix::Matrix(int i, int j)
{
	rows = i;
	columns = j;
}

void Matrix::setMatrix()
{
	cout << "Rows: " << rows << endl;
	cout << "Columns: " << columns << endl;
	cout << "Each (space) represents a column, each (enter) is a row." << endl;
	cout << "Please enter (int) matrix row elements separated by space: " << endl << endl;

	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < columns; j++)
		{
			cin >> a[i][j];
		}
	}
}

Matrix Matrix::operator+(const Matrix& m)
{
	Matrix sumMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				sumMatrix.a[i][j] = a[i][j] + m.a[i][j];
			}
		}
	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them with equal number of rows and columns." << endl;
		exit(0);
	}

	return sumMatrix;
}

Matrix Matrix::operator-(const Matrix& m)
{
	Matrix subMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				subMatrix.a[i][j] = a[i][j] - m.a[i][j];
			}
		}
	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them with equal number of rows and columns." << endl;
		exit(0);
	}
	return subMatrix;
}

Matrix Matrix::operator*(const Matrix& m)
{
	Matrix multMatrix(rows, columns);

	if (columns == m.rows)
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				multMatrix.a[i][j] = 0;
				for (int k = 0; k < m.columns; k++)
				{
					multMatrix.a[i][j] += a[i][k] * m.a[k][j];
				}
			}
		}

	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them (mXn)*(nXw)." << endl;
		exit(0);
	}
	return multMatrix;
}

ostream& operator<<(ostream& osObject, const Matrix& m)
{
	for (int r = 0; r < m.rows; r++)
	{
		osObject << endl;
		for (int c = 0; c < m.columns; c++)
		{
			osObject << m.a[r][c];
			osObject << " ";
		}
	}
	return osObject;
}


I didn't include source because there is a maximum character count :/.
Mar 24, 2017 at 8:54pm
Nevermind, source below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
//source.cpp
#include "iostream"
#include "Matrix.h"
using namespace std;

int main()
{
	int rows1 = 0, columns1 = 0, rows2 = 0, columns2 = 0, option = 0;
	bool wrongInput = false;
	bool exceededArray = false;

	while (option != 4)
	{
		do
		{
			cout << "--------------------------------------------------------" << endl;
			cout << "||            WELCOME TO THE MATRIX PROGRAM!          ||" << endl;
			cout << "|| We will create two matrices to perform arithmetic  ||" << endl;
			cout << "|| operations on them.                                ||" << endl;
			cout << "||----------------------------------------------------||" << endl;
			cout << "|| Before creating matrices please choose operation.  ||" << endl;
			cout << "||----------------------------------------------------||" << endl;
			cout << "|| addition       (1)    substraction (2)             ||" << endl;
			cout << "|| multiplication (3)    exit         (4)             ||" << endl;
			cout << "|| NOTE: max matrix size is 6x6                       ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "Enter option: "; cin >> option; cout << endl;
			wrongInput = cin.fail();
			cin.clear();
			cin.ignore(numeric_limits<streamsize>::max(), '\n');

		} while (wrongInput == false && option == 0);

		if (option == 4)
		{
			cout << "you have chosen to exit the program..." << endl;
			break;
		}
		else if (option == 1 || option == 2 || option == 3)
		{

			cout << "--------------------------------------------------------" << endl;
			cout << "||       Please enter (int) Matrix 1 rows:            ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "Matrix 1 rows: "; cin >> rows1; cout << endl;
			cout << "--------------------------------------------------------" << endl;
			cout << "||       Matrix 1  has " << rows1 << " rows!          ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "--------------------------------------------------------" << endl;
			cout << "||       Please enter (int) Matrix 1 columns:         ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "Matrix 1 columns: "; cin >> columns1; cout << endl;
			cout << "--------------------------------------------------------" << endl;
			cout << "||       Matrix 1  has " << columns1 << " columns!    ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			
			Matrix m1(rows1, columns1);

			if (m1.rows > maxRows || m1.columns > maxColumns)
			{
				exceededArray = true;
				break;
			}

			cout << "--------------------------------------------------------" << endl;
			cout << "||       Please enter (int) Matrix 2 rows:            ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "Matrix 2 rows: "; cin >> rows2; cout << endl;
			cout << "--------------------------------------------------------" << endl;
			cout << "||       Matrix 2  has " << rows2 << " rows!          ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "--------------------------------------------------------" << endl;
			cout << "||       Please enter (int) Matrix 2 columns:         ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;
			cout << "Matrix 2 columns: "; cin >> columns2; cout << endl;
			cout << "--------------------------------------------------------" << endl;
			cout << "||       Matrix 2  has " << columns2 << " columns!    ||" << endl;
			cout << "--------------------------------------------------------" << endl << endl;

			Matrix m2(rows2, columns2);

			if (m2.rows > maxRows || m2.columns > maxColumns)
			{
				exceededArray = true;
				break;
			}

			switch (option)
			{
			case 1:
			{
				if (m1.rows == m2.rows && m1.columns == m2.columns)
				{
					Matrix sumMatrix(rows1, columns1);

					cout << "||       You have chosen to perform addition!         ||" << endl;

					cout << "||       Currently setting Matrix 1:                  ||" << endl;
					
					m1.setMatrix();
					
					cout << "||       Currently setting Matrix 2:                  ||" << endl;
					
					m2.setMatrix();
					
					sumMatrix = m1 + m2;

					
					cout << "Matrix one display: " << m1 << endl;
					
					cout << "Matrix two display: " << m2 << endl;
					

					cout << "Matrices result: " << sumMatrix << endl;
					
				}
				else
				{
					cout << "Matrices must be of the same dimension in order to add them. Operation denied." << endl;
					cout << "Returning to main menu..." << endl;
				}
				break;
			}
			case 2:
			{
				if (m1.rows == m2.rows && m1.columns == m2.columns)
				{
					Matrix subMatrix(rows1, columns1);

					cout << "--------------------------------------------------------" << endl;
					cout << "||       You have chosen to perform subtraction!      ||" << endl;
					cout << "--------------------------------------------------------" << endl << endl;

					cout << "--------------------------------------------------------" << endl;
					cout << "||       Currently setting Matrix 1:                  ||" << endl;
					cout << "--------------------------------------------------------" << endl << endl;
					m1.setMatrix();
					cout << "--------------------------------------------------------" << endl;
					cout << "||       Currently setting Matrix 2:                  ||" << endl;
					cout << "--------------------------------------------------------" << endl << endl;
					m2.setMatrix();

					subMatrix = m1 - m2;

					
					cout << "Matrix one display: " << m1 << endl;
					
					cout << "Matrix two display: " << m2 << endl;
					

					cout << "Matrices result: " << subMatrix << endl;
					
				}
				else
				{
					cout << "Matrices must be of the same dimension in order to subtract them. \nOperation denied. ";
					cout << "Returning to main menu..." << endl;
				}
				break;
			}
			case 3:
			{
				if (m1.columns == m2.rows)
				{
					Matrix multMatrix(rows1, columns2);

					
					cout << "||       You have chosen to perform multiplication!   ||" << endl;
					cout << "--------------------------------------------------------" << endl << endl;

					cout << "--------------------------------------------------------" << endl;
					cout << "||       Currently setting Matrix 1:                  ||" << endl;
					cout << "--------------------------------------------------------" << endl << endl;
					m1.setMatrix();
					cout << "--------------------------------------------------------" << endl;
					cout << "||       Currently setting Matrix 2:                  ||" << endl;
					cout << "--------------------------------------------------------" << endl << endl;
					m2.setMatrix();

					multMatrix = m1 * m2;

					cout << "--------------------------------------------------------" << endl;
					cout << "Matrix one display: " << m1 << endl;
					cout << "--------------------------------------------------------" << endl;
					cout << "Matrix two display: " << m2 << endl;
					cout << "--------------------------------------------------------" << endl;

					cout << "Matrices result: " << multMatrix << endl;
					cout << "--------------------------------------------------------" << endl << endl;
				}
				else
				{
					cout << "Matrices must have these dimensions (nXm)*(mXo) \n in order to perform multiplication." << endl;
					cout << "Operation denied. Returning to main menu..." << endl;
				}
				break;
			}
			}
			continue;
		}
		else
		{
			cout << "Wrong option, returning to main menu..." << endl;
			continue;
		}
	}
	if (exceededArray == true)
	{
		cout << "You have entered dimensions bigger than: " << "(" << maxRows << "X" << maxColumns << ")" << endl;
		cout << "Exiting program... " << endl;
	}

	return 0;
}
Mar 25, 2017 at 5:12am
moving from class Matrix to class template Matrix a few things to bear in mind are:
(a) there will be no class called Matrix any longer, it will be Matrix<T> from now on where T is the type parameter, so Matrix<int> is one class, Matric<double> another and so on ...
(b) the class declaration is prefaced with template <typename T> to identify it as a class template, all other data-members and member functions within the class template declaration remain unchanged and only within the class template declaration you can continue to use just Matrix instead of Matrix<T> ...
(c) ... however there might be a change in any friend functions declared within the class template declaration such as being used in the Matrix<T> class template to overload the stream insertion operator - the link within the program gives more details and you can choose another implementation than mine from the options available if you so wish
(d) outside the class template declaration, when you come to defining the member functions again the template <typename T> is required for each member function to tell the compiler that this is a class template method
(e) finally when you come to using the class template in main(), it can be instantiated like:
1
2
3
Matrix<int> m_int;
Matrix<double> m_double;
//etc 

now I'll leave you to try out the following program if you want, there might be a few niggles here and there but it should be more or less on the right path:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
constexpr auto maxRows = 6;
constexpr auto maxColumns = 6;

template <typename T>
class Matrix
{

public:

	size_t rows, columns;//since rows and cols are independent of the template type
	T a[maxRows][maxColumns];

public:
	Matrix(T, T);

	template <typename U>
	friend ostream& operator<<(ostream& os, const Matrix<U>& m);
	//http://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class

	void setMatrix();

	Matrix operator+(const Matrix& m);
	Matrix operator-(const Matrix& m);
	Matrix operator*(const Matrix& s);
};


template <typename T>
Matrix<T>::Matrix<T>(const size_t i, const size_t j)
{
	rows = i;
	columns = j;
}

template <typename T>
void Matrix<T>::setMatrix<T>()
{
	cout << "Rows: " << rows << endl;
	cout << "Columns: " << columns << endl;
	cout << "Each (space) represents a column, each (enter) is a row." << endl;
	cout << "Please enter (int) matrix row elements separated by space: " << endl << endl;

	for (size_t i = 0; i < rows; i++)
	{
		for (size_ j = 0; j < columns; j++)
		{
			cin >> a[i][j];//this will require operator >> to be overloaded for type T that is held in a
		}
	}
}

template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& m)
{
	Matrix<T> sumMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (size_t i = 0; i < rows; i++)
		{
			for (size_t j = 0; j < columns; j++)
			{
				sumMatrix.a[i][j] = a[i][j] + m.a[i][j];
			}
		}
	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them with equal number of rows and columns." << endl;
		exit(0);
	}

	return sumMatrix;
}

template <typename T>
Matrix<T> Matrix<T>::operator-(const Matrix<T>& m)
{
	Matrix<T> subMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				subMatrix.a[i][j] = a[i][j] - m.a[i][j];
			}
		}
	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them with equal number of rows and columns." << endl;
		exit(0);
	}
	return subMatrix;
}

template <typename T>
Matrix<T> Matrix<T>::operator*(const Matrix<T>& m)
{
	Matrix<T> multMatrix(rows, columns);

	if (columns == m.rows)
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				multMatrix.a[i][j] = 0;
				for (int k = 0; k < m.columns; k++)
				{
					multMatrix.a[i][j] += a[i][k] * m.a[k][j];
				}
			}
		}

	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them (mXn)*(nXw)." << endl;
		exit(0);
	}
	return multMatrix;
}

template <typename T>
ostream& operator<<(ostream& osObject, const Matrix<T>& m)
{
	for (int r = 0; r < m.rows; r++)
	{
		osObject << endl;
		for (int c = 0; c < m.columns; c++)
		{
			osObject << m.a[r][c];
			osObject << " ";
		}
	}
	return osObject;
}

Last edited on Mar 25, 2017 at 5:17am
Mar 25, 2017 at 8:04pm
Hello again gunnerfunner! Thank you for your awesome answer.

I "got rid" of the nibbles in the code you provided. It has no errors.

However, I have started a source.cpp to try and instantiate as you said "Matrix<int> m_int;" An error occurs "LNK1120" & "LNK2019" I think I know why but I am not fully sure how to solve it.

There is the obvious obstacle that I know I have to overcome which is to tell the compiler what to do with an <int>. Let me provide code and leave a question...

//Matrix.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#pragma once
#include "iostream"

using namespace std;

constexpr auto maxRows = 6;
constexpr auto maxColumns = 6;

template <typename T>
class Matrix
{

public:

	size_t rows, columns;//since rows and cols are independent of the template type
	T a[maxRows][maxColumns];

public:
	Matrix(size_t, size_t);

	template <typename U>
	friend ostream& operator<<(ostream& os, const Matrix<U>& m);
	//http://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class

	void setMatrix();

	Matrix operator+(const Matrix& m);
	Matrix operator-(const Matrix& m);
	Matrix operator*(const Matrix& s);
};


//Matrix.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
#include "Matrix.h"


template <typename T>
Matrix<T>::Matrix(const size_t i, const size_t j)
{
	rows = i;
	columns = j;
}

template <typename T>
void Matrix<T>::setMatrix()
{
	cout << "Rows: " << rows << endl;
	cout << "Columns: " << columns << endl;
	cout << "Each (space) represents a column, each (enter) is a row." << endl;
	cout << "Please enter (int) matrix row elements separated by space: " << endl << endl;

	for (size_t i = 0; i < rows; i++)
	{
		for (size_ j = 0; j < columns; j++)
		{
			cin >> a[i][j];//this will require operator >> to be overloaded for type T that is held in a
		}
	}
}

template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& m)
{
	Matrix<T> sumMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (size_t i = 0; i < rows; i++)
		{
			for (size_t j = 0; j < columns; j++)
			{
				sumMatrix.a[i][j] = a[i][j] + m.a[i][j];
			}
		}
	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them with equal number of rows and columns." << endl;
		exit(0);
	}

	return sumMatrix;
}

template <typename T>
Matrix<T> Matrix<T>::operator-(const Matrix<T>& m)
{
	Matrix<T> subMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				subMatrix.a[i][j] = a[i][j] - m.a[i][j];
			}
		}
	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them with equal number of rows and columns." << endl;
		exit(0);
	}
	return subMatrix;
}

template <typename T>
Matrix<T> Matrix<T>::operator*(const Matrix<T>& m)
{
	Matrix<T> multMatrix(rows, columns);

	if (columns == m.rows)
	{
		for (int i = 0; i < rows; i++)
		{
			for (int j = 0; j < columns; j++)
			{
				multMatrix.a[i][j] = 0;
				for (int k = 0; k < m.columns; k++)
				{
					multMatrix.a[i][j] += a[i][k] * m.a[k][j];
				}
			}
		}

	}
	else
	{
		cout << "The matrices seem to be out of order..." << endl;
		cout << "please try to make them (mXn)*(nXw)." << endl;
		exit(0);
	}
	return multMatrix;
}

template <typename T>
ostream& operator<<(ostream& osObject, const Matrix<T>& m)
{
	for (int r = 0; r < m.rows; r++)
	{
		osObject << endl;
		for (int c = 0; c < m.columns; c++)
		{
			osObject << m.a[r][c];
			osObject << " ";
		}
	}
	return osObject;
}


//source.cpp
1
2
3
4
5
6
7
8
9
10
11
12
#include "Matrix.h"

using namespace std;

int main()
{
	size_t rows = 1;
	size_t columns = 2;

	Matrix<int> m_int(rows, columns);

}


I need to make another class to handle Matrix<int>... If so, should it be a new class file that is "Matrix<int>.h" and "Matrix<int>.cpp" Or should I do it in the already existing "Matrix.h""Matrix.cpp"?
Last edited on Mar 25, 2017 at 8:05pm
Mar 26, 2017 at 5:20am
class templates have a few quirks regarding separation b/w header and source files:
http://stackoverflow.com/questions/40671478/templated-classes-using-header-and-source-file
for convenience i've put everything into the header file below, you can separate them out into header and source based on above link's guidelines if you wish:
also upon further review the following felt like a bit of a cop-out:
1
2
constexpr auto maxRows = 6;
constexpr auto maxColumns = 6;
since we're not always going to be dealing with 6X6 matrices, there is no need to allocate memory for such. the alternative would be to dynamically allocate the 2d array underlying each Matrix object - this does introduce some additional complexity, particularly re memory management, but is more sensible
now regarding the "additional complexity" bit, as your class is managing resources (as the use of the new operator within the ctor entails) you'll need to write a dtor to delete the resources managed by the ctor. However, just a dtor is not enough. If a copy is made of the object, then the copy will point to the same memory as the original object and so you need to define a copy ctor (and copy assignment operator) unless you decide to delete both these functions which would make the class non-copyable.
However, in C++11 world, this may not quite the end of the story because we might also need to take care of move ctor and move assignment operator - so these may have to be defined as well. for convenience i've provided the definition of the dtor to get you started and here are some links on the subject:
http://stackoverflow.com/questions/4172722/what-is-the-rule-of-three
http://stackoverflow.com/questions/4782757/rule-of-three-becomes-rule-of-five-with-c11
finally, it would be incomplete not to mention that there are other, simpler way of defining Matrix type classes using the standard library containers like std::vector that takes care of the memory management far more simply. you can pick up some ideas here: https://cboard.cprogramming.com/cplusplus-programming/171694-issues-reading-series-2d-matrices-file.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
//#include <iostream>
#ifndef MATRIX_H_
#define MATRIX_H_

template <typename T>
class Matrix
{
    public:

        size_t rows = 0;
        size_t columns = 0;//since rows and cols are independent of the template type
        T** a = nullptr;
        //std::unique_ptr<std::unique_ptr<T>> a;

    public:
        Matrix(const size_t, const size_t);
        ~Matrix();

        template <typename U>
        friend std::ostream& operator<<(std::ostream& os, const Matrix<U>& m);
        //http://stackoverflow.com/questions/4660123/overloading-friend-operator-for-template-class

        void setMatrix();

        Matrix operator+(const Matrix& m);
        Matrix operator-(const Matrix& m);
        Matrix operator*(const Matrix& m);
};
template <typename T>
Matrix<T>::Matrix(const size_t i, const size_t j) : rows(i), columns(j)
{
	a = new T*[rows];
	for (size_t i = 0; i < rows; ++i)
    {
        a[i] = new T[columns];
    }
}
template <typename T>
void Matrix<T>::setMatrix()
{
	std::cout << "Rows: " << rows << "\n";
	std::cout << "Columns: " << columns << "\n";
	std::cout << "Each (space) represents a column, each (enter) is a row." << "\n";
	std::cout << "Please enter matrix row elements separated by space: " << "\n\n";

	for (size_t i = 0; i < rows; i++)
	{
		for (size_t j = 0; j < columns; j++)
		{
			std::cin >> a[i][j];//this will require operator >> to be overloaded for type T that is held by a
		}
	}
}
template <typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& m)
{
	Matrix<T> sumMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (size_t i = 0; i < rows; i++)
		{
			for (size_t j = 0; j < columns; j++)
			{
				sumMatrix.a[i][j] = a[i][j] + m.a[i][j];
			}
		}
	}
	else
	{
		std::cout << "The matrices seem to be out of order..." << "\n";
		std::cout << "please try to make them with equal number of rows and columns." << "\n";
    }
    return sumMatrix;
}

template <typename T>
Matrix<T> Matrix<T>::operator-(const Matrix<T>& m)
{
	Matrix<T> subMatrix(rows, columns);

	if ((rows == m.rows) && (columns == m.columns))
	{
		for (size_t i = 0; i < rows; i++)
		{
			for (size_t j = 0; j < columns; j++)
			{
				subMatrix.a[i][j] = a[i][j] - m.a[i][j];
			}
		}
	}
	else
	{
		std::cout << "The matrices seem to be out of order..." << "\n";
		std::cout << "please try to make them with equal number of rows and columns." << "\n";
    }
	return subMatrix;
}

template <typename T>
Matrix<T> Matrix<T>::operator*(const Matrix<T>& m)
{
	Matrix<T> multMatrix(rows, columns);

	if (columns == m.rows)
	{
		for (size_t i = 0; i < rows; i++)
		{
			for (size_t j = 0; j < columns; j++)
			{
				multMatrix.a[i][j] = 0;
				for (size_t k = 0; k < m.columns; k++)
				{
					multMatrix.a[i][j] += a[i][k] * m.a[k][j];
				}
			}
		}

	}
	else
	{
		std::cout << "The matrices seem to be out of order..." << "\n";
		std::cout << "please try to make them (mXn)*(nXw)." << "\n";
    }
	return multMatrix;
}
template <typename T>
Matrix<T>::~Matrix()
{
    for (size_t i = 0; i < rows; ++i)
    {
        delete [] a[i];
    }
    delete [] a;
}
template <typename T>
std::ostream& operator << (std::ostream& osObject, const Matrix<T>& m)
{
	for (size_t r = 0; r < m.rows; r++)
	{
		osObject << "\n";
		for (size_t c = 0; c < m.columns; c++)
		{
			osObject << m.a[r][c] << " ";
		}
	}
	return osObject;
}
#endif // MATRIX_H_ 



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include "test.h"

const size_t rows = 1;
const size_t columns = 2;

//using namespace std;
//http://stackoverflow.com/questions/1452721/why-is-using-namespace-std-considered-bad-practice

int main()
{
    Matrix<int> m_int(2, 2);
    Matrix<int> n_int(2, 2);
    m_int.setMatrix();
    n_int.setMatrix();
    auto mn_int = m_int * n_int;
    std::cout << mn_int ;
}
/* SAMPLE PROGRAM
Rows: 1
Columns: 2
Each (space) represents a column, each (enter) is a row.
Please enter (int) matrix row elements separated by space:

4 5
Rows: 1
Columns: 2
Each (space) represents a column, each (enter) is a row.
Please enter (int) matrix row elements separated by space:

6 7

10 12

Rows: 2
Columns: 2
Each (space) represents a column, each (enter) is a row.
Please enter matrix row elements separated by space:

3
3
3
3
Rows: 2
Columns: 2
Each (space) represents a column, each (enter) is a row.
Please enter matrix row elements separated by space:

3
3
3
3

18 18
18 18

*/

I need to make another class to handle Matrix<int>... If so, should it be a new class file that is "Matrix<int>.h" and "Matrix<int>.cpp" Or should I do it in the already existing "Matrix.h""Matrix.cpp"?
you don't need anything else apart from the one header file and you can declare as many Matrix<T> classes from here on as you wish e.g. Matrix<int>, Matrix<float>, Matrix<double>, Matrix<someCustomType> as long as all the relevant operators are defined for someCustomType
ps: note there is still a bug in your program when it comes to mulitplying asymmetric matrices, e.g. a (2X1) with a (1X2) the program aborts. please take a look
Mar 26, 2017 at 3:15pm
Consider using std::valarray<> to implement numeric operation on matrices.
http://en.cppreference.com/w/cpp/numeric/valarray

In addition to the advantages common to using containers from the standard library (automatic resource management, zero-programmer-cost support for move semantics), std::valarray<> also has excellent support for mathematical operations.

For instance, here's a skeletal implementation wrapping std::valarray<>:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
#include <iostream>
#include <type_traits>
#include <valarray>
#include <initializer_list>

template < typename T > struct matrix
{
    static_assert( std::is_arithmetic<T>::value, "non-arithmetic types are not supported" ) ;
    static_assert( !std::is_reference<T>::value, "can't have a matrix of references" ) ;
    static_assert( !std::is_const<T>::value &&
                   !std::is_volatile<T>::value, "can't have a matrix of cv-qualified types" ) ;

    matrix( std::size_t nrows, std::size_t ncols ) : nrows(nrows), ncols(ncols), data(nrows*ncols) {}
    matrix( std::size_t nrows, std::size_t ncols, std::initializer_list<T> ilist )
        : nrows(nrows), ncols(ncols), data(nrows*ncols)
    {
        std::size_t i = 0 ;
        for( auto& v : ilist ) { if( i < data.size() ) data[i++] = v ; else break ; }
    }

    // rule of zero: http://en.cppreference.com/w/cpp/language/rule_of_three

    // row and column access
    std::slice_array<T> operator[] ( std::size_t row_num ) { return row(row_num) ; }
    std::slice_array<T> row( std::size_t row_num ) { return data[ std::slice( row_num*ncols, ncols, 1 ) ] ; ; }
    std::slice_array<T> col( std::size_t col_num ) { return data[ std::slice( col_num, nrows, ncols ) ] ; }

    std::valarray<T> operator[] ( std::size_t row_num ) const { return row(row_num) ; }
    std::valarray<T> row( std::size_t row_num ) const { return data[ std::slice( row_num*ncols, ncols, 1 ) ] ; ; }
    std::valarray<T> col( std::size_t col_num ) const { return data[ std::slice( col_num, nrows, ncols ) ] ; }

    // compound arithmetic operators
    matrix& operator+= ( const matrix& that ) { data += that.data ; return *this ; }
    matrix& operator+= ( const T& v ) { data += v ; return *this ; }

    matrix& operator-= ( const matrix& that ) { data -= that.data ; return *this ; }
    matrix& operator-= ( const T& v ) { data -= v ; return *this ; }

    // TO DO: likewise for other compound arithmetic operators

    // makes a whole lot more functionality available
    std::valarray<T>& view_as_valarray() { return data ; }
    const std::valarray<T>& view_as_valarray() const { return data ; }

    private:
        std::size_t nrows ;
        std::size_t ncols ;
        std::valarray<T> data ;

    // arithmetic operators
    friend matrix operator+ ( matrix a, const matrix& b ) { return a += b ; }
    friend matrix operator+ ( matrix a, const T& b ) { return a += b ; }
    friend matrix operator+ ( const T& a, matrix b ) { return b += a ; }

    friend matrix operator- ( matrix a, const matrix& b ) { return a -= b ; }
    friend matrix operator- ( matrix a, const T& b ) { return a -= b ; }

    // TO DO: other arithmetic operators

    // TO DO: classic operations transpose, matrix multiply etc.

    friend std::ostream& operator<< ( std::ostream& stm, const matrix& mtx )
    {
        std::size_t cnt = 0 ;
        for( const auto& v : mtx.data ) stm << v << ( ++cnt % mtx.ncols == 0 ? '\n' : ' ' ) ;
        return stm ;
    }

    // TO DO: stream insertion operator
};

static_assert( std::is_nothrow_move_constructible< matrix<double> >::value &&
               std::is_nothrow_move_assignable< matrix<int> >::value,
               "broken compiler and/or library" ) ; // sanity check

int main()
{
    matrix<int> m1( 3, 5, { 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 } ) ;
    const matrix<int> m2( 3, 5, { 33, 38, 32, 35, 39, 37, 34, 36, 31, 40, 41, 42, 43, 44, 45 } ) ;

    std::cout << "m1:\n" << m1 << "\nm2:\n" << m2 << "\nm1+m2:\n" << m1+m2
              << "\nm1-m2:\n" << m1-m2 << "\nm1-1:\n" << m1-1 << "\n100+m1:\n" << 100+m1 << '\n' ;

    m1.row(1) = 17 ;
    std::cout << "row(1) = 17 ;\n" << m1 << '\n' ;

    m1.col(3) = -678 ;
    std::cout << "col(3) = -678 ;\n"<< m1 << '\n' ;

    m1.col(2) *= std::valarray<int>{ 20, 30, 40 } ;
    std::cout << "col(2) *= std::valarray<int>{ 20, 30, 40 } ;\n"<< m1 << '\n' ;

    auto& va = m1.view_as_valarray() ;
    va[ va>21 ] = 99 ; // assign 99 to all elements greater than 21
    std::cout << "va[ va>21 ] = 99 ;\n" << m1 << '\n' ;
}

http://coliru.stacked-crooked.com/a/9aa5dba66ac4b3f4
Topic archived. No new replies allowed.