I am developing a matrix class for my personal library. I am using a template class (Class T) because I want a matrix to be of any numeric or boolean format (and don't want to retype everything). So what I would like to do is have the operater+= allow a scalar or a matrix. However, I would like to be able to add two matrices together regardless of their numeric format (Class U).
I get the following compile errors.
error: prototype for 'JecMatrix<T>& JecMatrix<T>::operator+=(const JecMatrix<U>&)' does not match any in class 'JecMatrix<T>'
error: candidates are: template<class T> template<class U> JecMatrix& JecMatrix::operator+=(const U&)
error: template<class T> template<class U> JecMatrix& JecMatrix::operator+=(const JecMatrix<U>&)
Does anyone have a solution to this? I've included the entire class below.
#ifndef JECMATRIX_H
#define JECMATRIX_H
#include <typeinfo>
#include <QTime>
#include <QList>
#include <JecLibrary_global.h>
#include <JecUtils.h>
template<class T>
class JECLIBRARYSHARED_EXPORT JecMatrix
{
public:
JecMatrix();
JecMatrix(const int& rows, const int& cols);
JecMatrix(const QList<QList<T> >& sourceMatrix);
~JecMatrix();
JecMatrix<T>& operator=(const JecMatrix<T>& rhs);
bool operator!=(const JecMatrix<T>& rhs) const;
bool operator==(const JecMatrix<T>& rhs) const;
template<class U> JecMatrix<T>& operator+=(const JecMatrix<U> &rhs) throw(QString);
template<class U> JecMatrix<T>& operator+=(const U& rhs) throw(QString);
};
template<class T>
JecMatrix<T>::JecMatrix()
{
T var;
assertNumber(var);
}
template<class T>
JecMatrix<T>::JecMatrix(const int &rows, const int &cols)
{
for (int r = 0; r < rows; ++r)
{
matrix.append(QList<T>());
for (int c = 0; c < cols; ++c)
{
matrix[r].append(0);
}
}
}
template<class T>
JecMatrix<T>::JecMatrix(const QList<QList<T> >& sourceMatrix)
{
for (int r = 0; r < sourceMatrix.length(); ++r)
{
matrix.append(QList<T>());
for (int c = 0; c < sourceMatrix.at(r).length(); ++c)
{
matrix[r].append(sourceMatrix.at(r).at(c));
}
}
}
template<class T>
JecMatrix<T>& JecMatrix<T>::operator=(const JecMatrix<T>& rhs)
{
if (this == &rhs)
{
return *this;
}
this->id = rhs.id; // The id of the Base.
this->minerals = rhs.minerals; // The minerals available at that base.
this->vespene = rhs.vespene; // The gas available at that base.
this->buildings = rhs.buildings; // The units the player owns during this second. The outer QList holds the types of units and the inner holdes the unique coppies of that unit.
this->units = rhs.units; // The units the player owns during this second. The outer QList holds the types of units and the inner holdes the unique coppies of that unit.
return *this;
}
template<class T,class U>
JecMatrix<T>& JecMatrix<T>::operator+=(const JecMatrix<U> &rhs) throw(QString)
{
// Perform type checking.
U var;
assertNumber(var);
// Perform size checking.
if (rhs.getRows() != getRows()) {
throw ("To add the matrices they must have the same number of rows and columns. Matrix a has "
+ QString::number(a.getRows())
+ " rows and matrix b has "
+ QString::number(b.getRows()) + " rows.");
}
if (rhs.getCols() != getCols()) {
throw ("To add the matrices they must have the same number of rows and columns. Matrix a has "
+ QString::number(a.getCols())
+ " cols and matrix b has "
+ QString::number(b.getCols()) + " cols.");
}
double result[][] = new double[a.getRows()][a.getCols()];
// Add the matrices.
for (int resultRow = 0; resultRow < a.getRows(); resultRow++) {
for (int resultCol = 0; resultCol < a.getCols(); resultCol++)
{
matrix[resultRow][resultCol] += rhs.matrix[resultRow][resultCol];
}
}
return *this;
}
template<class T, class U>
JecMatrix& JecMatrix::operator+=(const U& rhs) throw(QString)
{
// Perform type checking.
U var;
assertNumber(var);
// Perform the scalar addition.
for (int r = 0; r < matrix.length(); ++r)
{
for (int c = 0; c < matrix.at(0).length(); ++c)
{
matrix[r][c] += rhs;
}
}
}
#endif // JECMATRIX_H
Edit: removed irrelevant code.
Say it like this:
template <class T>
template <class U>
JecMatrix<T>& JecMatrix<T>::operator+=(const JecMatrix<U> &rhs) throw(QString)
{
// ...
}
The two template declarations have to be separate.
Related
I created a Matrix template class to work with matrixes of various types (int, float, 2D-points, etc.)
template<typename Type>
class Matrix {
...
};
I added some operators like +, -, *, /. These functions also need to be templated, because I want to multiply a Matrix type by float , or by a Matrix.
Here is my multiplication implementation:
template<typename T>
Matrix operator*(const T &other) const {
Matrix temp(*this);
temp *= other;
return temp;
}
Matrix &operator*=(const Matrix &other) {
auto temp = Matrix(rows, other.columns);
for (int i = 0; i < rows; i++)
for (int j = 0; j < other.columns; j++) {
temp.matrix[i][j] = Type();
for (int k = 0; k < other.rows; k++)
temp.matrix[i][j] += matrix[i][k] * other.matrix[k][j];
}
AllocMatrixData(temp.rows, temp.columns);
matrix = temp.matrix;
return *this;
}
template<typename T>
Matrix &operator*=(const T value) {
for (ProxyVector<Type> &line : matrix) <- ProxyVector is just a wrapper
line *= value;
return *this;
}
I want my Matrix object to be on the left side, so I can do this:
Matrix * 5
However I can't do this:
5 * Matrix
So I added a function that can take a type T as the first argument and Matrix as second.
template<typename T>
friend Matrix<Type> operator*(const T Value, const Matrix<Type> &other)
{
return other * Value;
}
But now Matrix*Matrix multiplication is ambiguous. I think I understand why - I have two functions that take T and Matrix and in this case T can be the Matrix type too. So how do I fix this?
When multiplying 2 matrices, both the member operator and operator* are applicable and have equal precedence regarding the decision of the overload to choose.
Use concepts (or SFINAE prior to C++20) to determine, if the parameter is a matrix or a scalar. This allows you to define overloads that only take part in overload resolution for the proper parameter types.
I recommend being consistent with the location of the implementation of the operator btw: If you implement a symetric operator where one of the overloads need to be defined at namespace scope, define both overloads at namespace scope; this allows you to keep the logic of both versions close together making it easier to maintain the logic.
In the following case we simply define everything that's not a matrix a scalar.
template<class T>
struct Matrix
{
};
template<class T>
struct IsMatrixHelper : std::false_type {};
template<class T>
struct IsMatrixHelper<Matrix<T>> : std::true_type {};
template<class T>
concept Scalar = !IsMatrixHelper<T>::value;
template<class T, Scalar U>
auto operator*(Matrix<T> const& m, U scalar)
{
return Matrix<decltype(std::declval<T>()* std::declval<U>())>{};
}
template<Scalar T, class U>
auto operator*(T scalar, Matrix<U> const& m)
{
return Matrix<decltype(std::declval<T>()* std::declval<U>())>{};
}
template<class T, class U>
auto operator*(Matrix<T> const& m1, Matrix<U> const& m2)
{
return Matrix<decltype(std::declval<T>()* std::declval<U>())>{};
}
static_assert(std::is_same_v<decltype(std::declval<Matrix<int>>() * std::declval<Matrix<long long>>()), Matrix<long long>>);
static_assert(std::is_same_v<decltype(std::declval<Matrix<long long>>() * std::declval<int>()), Matrix<long long>>);
static_assert(std::is_same_v<decltype(std::declval<long long>() * std::declval<Matrix<int>>()), Matrix<long long>>);
I'm having some problem with my std::forward constructor for my template "matrix" class. Basically i want to set a matrix of type float and size 4 equal to the sum of 2 matrices of type float and size 3. I do this inside of my struct 'matrix_struct' in the function 'test'. However, MSVC error tells me that "'static_cast': cannot convert from 'matrix' to 'float'" and whenever I inspect the error it takes me to the 3rd matrix constructor with std::forward.
///////////////////////////////////
somefile.hpp
#pragma once
#include "matrix.hpp"
using matrix3 = matrix<float, 3>;
using matrix4 = matrix<float, 4>;
struct matrix_struct {
matrix4 sum;
void test(const matrix3& a, const matrix3& b)
{
sum = a + b;
}
}
///////////////////////////////////
matrix.hpp
#pragma once
#include <array>
template <typename t, size_t dim>
class matrix
{
public:
matrix() { data.fill(static_cast<t>(0) }
explicit matrix(const std::array<t, dim>& a) : data(a) {}
template <typename... args_t>
matrix(args_t... args) : data{ static_cast<t>(std::forward<args_t>(args))... } }
public:
t& at(const size_t index)
{
return data.at(index >= dim ? dim - 1 : index);
}
const t& at(const size_t index) const
{
return data.at(index >= dim ? dim - 1 : index);
}
public:
matrix& operator = (const matrix<t, dim>& other)
{
for (size_t i = 0; i < dim; ++i) {
at(i) = other.at(i);
}
return *this;
}
matrix& operator = (const std::array<t, dim>& other)
{
for (size_t i = 0; i < dim; ++i) {
at(i) = other.at(i);
}
return *this;
}
matrix& operator = (const t& other)
{
for (size_t i = 0; i < dim; ++i) {
at(i) = other;
}
return *this;
}
public:
matrix operator + (const matrix<t, dim>& other) const
{
matrix<t, dim> ret;
for (size_t i = 0; i < dim; ++i) {
ret.at(i) = at(i) + other.at(i);
}
return ret;
}
matrix operator + (const std::array<t, dim>& other) const
{
matrix<t, dim> ret;
for (size_t i = 0; i < dim; ++i) {
ret.at(i) = at(i) + other.at(i);
}
return ret;
}
matrix operator + (const t& other) const
{
matrix<t, dim> ret;
for (size_t i = 0; i < dim; ++i) {
ret.at(i) = at(i) + other;
}
return ret;
}
private:
std::array<t, dim> data;
};
Template constructors are problematic. They often create code that is a better candidate than your other constructors.
The general solution is to disable the template if its decayed type matches the class you are writing.
example:
struct MyClass
{
template
<
class Arg,
class...Rest,
std::enable_if_t
<
! std::is_same
<
std::decay_t<Arg>,
MyClass
>::value
>* = nullptr
>
MyClass(Arg&& arg, Rest&&...rest)
{
// code to construct from something that's not MyClass
// this will no longer hijack copy constructors etc.
}
};
The first problem of your code sample is addressed by #RichardHodges's answer.
Assuming you include his solution to overcome tricky copy/move constructor selection, another problem remains: you do not offer a matrix promotion/demotion service through your constructors/assignment operators.
Therefore, the following line in your test function:
sum = a + b; // a + b is a matrix<float, 3>, sum a matrix<float, 4>
Will trigger a call to the variadic template constructor and fail.
Starting from Richard's solution, you need to tweak a bit the SFINAE condition to extend it to matrices of any size. To do so, we will need a little is_matrix trait:
template <typename T, size_t Dim>
class matrix;
template <typename T>
struct is_matrix : std::false_type {};
template <typename Num, size_t Size>
struct is_matrix<matrix<Num, Size> > : std::true_type {
using value_type = Num;
};
Now the variadic template constructor becomes:
template <typename t, size_t dim>
class matrix
{
/* ... */
public:
/* ... */
template
<
class Arg,
class...Rest,
std::enable_if_t
<
! std::is_matrix
<
std::decay_t<Arg>
>::value
>* = nullptr
>
matrix(Arg&& arg, Rest&&...rest)
{
// code to construct from something that's not a matrix
// this will no longer hijack copy constructors etc.
}
};
Then, we need to add the proper matrix constructor along with the proper friend declaration:
template <typename t, typename dim>
class matrix {
public:
template <typename OtherT, size_t OtherDim>
friend class matrix;
template <size_t OtherDim>
matrix(matrix<t, OtherDim> const& other) {
size_t i = 0;
for (; i < min(OtherDim, dim); ++i) {
data[i] = other.data[i];
}
for(; i < dim; ++i) {
data[i] = t();
}
}
template <typename OtherT,
size_t OtherDim>
matrix(matrix<OtherT, OtherDim> const&) {
static_assert(std::is_same<t, OtherT>::value,
"value_type mismatch between matrices!");
}
/* ... */
};
Note: You need the friend declaration because matrix<Type1, Dim1> and matrix<Type2, Dim2> are completely different types whenever Type1 != Type2 or Dim1 != Dim2 and as such, you cannot access matrix<OtherT, OtherDim>'s private/protected members in matrix<t, dim> without that friend declaration.
This implementation will initialize the target matrix by filling its data member with the content of the given matrix when the value types match:
If the given matrix is bigger, it will be truncated.
If the given matrix is smaller, the remaining elements will be 0 initialized
If the value types don't match, the less specialized matrix<OtherT, OtherDim> constructor is the only available overload and it triggers a compiler error through a static_assert.
You would also need to define the equivalent assigment operators... Which I left as exercises.
A demo of these constructors in action can be found on Coliru
I'm trying to write a class View to serve as a view into another container, (a sparse matrix class, but that should be unimportant for the question).
View should contain references (e.g. std::reference_wrapper) to a selection of elements in the container, and have methods returning references to those elements, as well as an assignment operator making one block equal to another.
My problem is that I want View to be able to take values in addition to references: both be constructed from values as a non-reference instance to be used in assignments, and assign values to single elements in a reference instance.
An MVE of the code so far is:
#include <array>
template<typename T, size_t size>
class View
{
private:
std::array<T, size> _values;
public:
View(const std::array<T, size> & values)
: _values{ values } { }
// ----------
View<T, size> & operator=(const View<T, size> & other)
{
for ( size_t i = 0; i < size; ++i ) {
this->get(i) = other.get(i);
}
return *this;
}
// ----------
T & get(size_t idx)
{
return _values.at(idx);
}
const T & get(size_t idx) const
{
return _values.at(idx);
}
};
It can be used like this:
#include <functional>
#include <iostream>
int main()
{
int values[5] = { 1, 2, 3, 4, 5 };
View<int, 2> v1{
{values[0], values[1]}
};
View<std::reference_wrapper<int>, 2> v2{
{values[3], values[4]}
};
// WHAT WORKS
v1.get(0) = 10; // can assign to the non reference `View<int, size>`,
// works as intended
v2.get(0) += 9; // can increment through the reference wrappers,
// this also works as intended
// WHAT THAT DOES NOT WORK
// v2 = v1; // nether of these work, as there is no conversion
// v1 = v2; // between `View<std::reference_wrapper<int>, size>`
// and `View<int, size>`. It is the first expression
// that is of most interest
// v2.get(1) = 10; // this doesn't work as the return is a
// `std::reference_wrapper<int>`, not a
// reference to an `int`
v2.get(1).get() = 10; // this works as a work-around to
// this problem, but it feels clunky, and it
// makes the interface between the two types
// different
for ( size_t i = 0; i < 2; ++i ) {
std::cout << v1.get(i) << " ";
}
std::cout << std::endl;
for ( size_t i = 0; i < 5; ++i ) {
std::cout << values[i] << " ";
}
std::cout << std::endl;
}
This should output:
10 2
1 2 3 13 10
I'm using clang++ to compile on Ubuntu 15.10.
So specifically,
How should I implement the assignment operator to allow View<T, size> and View<std::reference_wrapper<T>, size> to be assigned to each other (or at least the former to be assigned to latter). Creating two versions
View<T, size> & operator=(const View<T, size> & other);
View<T, size> & operator=(
const View<std::reference_wrapper<T>, size> & other);
does not work, (as a View<std::reference_wrapper<T>, size> then would need a View<std::reference_wrapper<std::reference_wrapper<T> >, size> for the second overload).
How can I write the get(size_t idx) methods such that the return is T & for bothView<T, size> and View<std::reference_wrapper<T>, size>?
I have a feeling this can be accomplished by using templates somehow, but I'm still quite new to template programming so I'm a bit lost.
Here is a way to make get() return T& for T and std::reference_wrapper<T>:
template <typename T>
struct get_value_type {
using type = T;
};
template <typename T>
struct get_value_type<std::reference_wrapper<T>> {
using type = T;
};
template<typename T, size_t size>
class View {
using value_type = typename get_value_type<T>::type;
value_type & get(size_t idx) {
return _values.at(idx);
}
const value_type & get(size_t idx) const {
return _values.at(idx);
}
};
The get_value_type template help us obtain T from both T and std::reference_wrapper<T>, then you simply change the return type of get() to value_type, and since std::reference_wrapper<T> is implicitly convertible to T& it works.
Now that you have access to value_type, you can use it to create your two operator=:
View& operator= (const View<value_type, size> & other) {
for (size_t i = 0; i < size; ++i) {
this->get(i) = other.get(i);
}
return *this;
}
View& operator=(const View<std::reference_wrapper<value_type>, size> & other) {
for (size_t i = 0; i < size; ++i) {
this->get(i) = other.get(i);
}
return *this;
}
In case you want to allow assignment from different view (e.g. a view of int to a view of double), you could use a templated version:
template <typename U>
View<T, size> & operator=(const View<U, size> & other) {
for (size_t i = 0; i < size; ++i) {
this->get(i) = other.get(i);
}
return *this;
}
A small addition that may be a bit off-topic but instead of having an std::array attribute, you could inherit from std::array like the following:
template<typename T, size_t Size>
struct View: public std::array<T, Size> {
using array_type = std::array<T, Size>;
using value_type = typename get_value_type<T>::type;
View (std::array<T, Size> const& values) : array_type (values) { }
View& operator=(const View<value_type, Size> & other) {
for (size_t i = 0; i < Size; ++i) {
(*this)[i] = other[i];
}
return *this;
}
View& operator=(const View<std::reference_wrapper<value_type>, Size> & other) {
for (size_t i = 0; i < Size; ++i) {
(*this)[i] = other[i];
}
return *this;
}
value_type & operator[](size_t idx) {
return array_type::operator[](idx);
}
const value_type & operator[](size_t idx) const {
return array_type::operator[](idx);
}
};
This would allow you to use a lot of stuff from the standard library on your View without having to redefine anything.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
I was staring at this all night before I decided to give up and go to sleep - a few hours into it again today, I still don't have it. I am unable to figure out how to change the const-ness and parameters to correctly return (on the operator+=). Any help?
The error pops up at the return this statement in the operator+= overload.
#include <iostream>
#include <vector>
template <typename T> class Matrix {
private:
unsigned rows, cols;
public:
Matrix();
~Matrix();
Matrix(const Matrix<T>& rhs);
Matrix(unsigned _rows, unsigned _cols);
std::vector<std::vector<T>> matrix;
Matrix<T>& operator=(Matrix<T> rhs);
//Matrix mathematical operations
Matrix<T> operator+(const Matrix<T>& rhs);
Matrix<T>& operator+=(const Matrix<T>& rhs);
// Access the individual elements
T& operator()(const unsigned& row, const unsigned& col);
const T& operator()(const unsigned& row, const unsigned& col) const;
// Access the row and column sizes
unsigned get_rows() const;
unsigned get_cols() const;
void swap(Matrix<T>& rhs);
};
template<typename T>
Matrix<T>::Matrix() {}
template<typename T>
Matrix<T>::~Matrix() {}
// Parameter Constructor
template<typename T>
Matrix<T>::Matrix(unsigned _rows, unsigned _cols) {
matrix.resize(_rows);
for (unsigned i = 0; i < _rows; i++)
matrix[i].resize(_cols, 1); // change back to 0 after debug
rows = _rows;
cols = _cols;
}
template<typename T>
Matrix<T>& Matrix<T>::operator=(Matrix<T> rhs) {
swap(rhs);
return *this;
}
template<typename T>
Matrix<T> Matrix<T>::operator+(const Matrix<T>& rhs) {
Matrix<T> result(*this);
result += rhs;
return result;
}
template<typename T>
Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& rhs) {
for (unsigned i = 0; i < rows; i++) {
for (unsigned j = 0; j < cols; j++) {
this->matrix[i][j] += rhs(i, j);
}
}
return this; // error pops up here
}
// Access the individual elements
template<typename T>
T& Matrix<T>::operator()(const unsigned& row, const unsigned& col) {
return this->matrix[row][col];
}
// Access the individual elements (const)
template<typename T>
const T& Matrix<T>::operator()(const unsigned& row, const unsigned& col) const{
return this->matrix[row][col];
}
// Get the number of rows of the matrix
template<typename T>
unsigned Matrix<T>::get_rows() const {
return this->rows;
}
//Get the number of columns of the matrix
template<typename T>
unsigned Matrix<T>::get_cols() const {
return this->cols;
}
template<typename T>
void Matrix<T>::swap(Matrix<T>& rhs) {
using std::swap;
swap(this->rows, rhs.rows);
swap(this->cols, rhs.cols);
swap(this->matrix, rhs.matrix);
}
// for debugging
template<typename T>
void print_matrix(Matrix<T>& matrix) {
for (int i = 0; i < matrix.get_rows(); i++) {
for (int j = 0; j < matrix.get_cols(); j++) {
std::cout << matrix(i, j) << " ";
}
std::cout << " " << std::endl;
}
}
int main(int argc, char **argv) {
Matrix<double> matrix1(5, 5);
Matrix<double> matrix2(5, 5);
// Start testing
Matrix<double> matrix3 = matrix1 + matrix2;
print_matrix(matrix1);
std::getchar();
return 0;
}
In the += operator, you probably want:
Matrix<T>& Matrix<T>::operator+=(const Matrix<T>& rhs) {
//....
return *this;
//^^
}
The linker error is because you did not define:
Matrix(const Matrix<T>& rhs);
I am using Boost-Operatators to construct a matrix class. (A toy project). However, I run into issues when I want to mix matrices of different element types.
Basically I have a template class Matrix<T>, where T is the element type of that matrix. I'm using Boost-Operators to define operators between instances of Matrix<T> (e.g. element-wise add), between Matrix<T> and T (e.g. scalar multiplication), and if possible also between Matrix<T> and Matrix<U> (e.g. real matrix plus complex matrix).
The boost operators support one, or two template arguments. One if you want operators between two objects of the same type, and two if you want mixed operators.
template<typename T>
class Matrix : boost::addable<Matrix<T>> // Add another matrix of same type.
boost::multiplyable2<Matrix<T>,T> // Scalar multiplication with a `T`.
However, I cannot give Matrix<U> as a second argument, because then my class would have two template arguments and the type would depend on which matrices I can operate with.
template<typename T, typename U>
class Matrix : boost::addable2<Matrix<T,U>,Matrix<U,?>> // Now I have two template arguments.
// That's certainly not what I want!
I also tried implementing my own version of boost::addable, but this didn't work either. The compiler complains about an uncomplete type.
template<class Derived>
class Addable {
template<class Other>
friend Derived operator+(Derived lhs, const Other &rhs) {
return lhs += rhs;
}
template<class Other>
friend Derived operator+(const Other &lhs, Derived rhs) {
return rhs += lhs;
}
};
Another approach was to define a cast constructor from Matrix<U> to Matrix<T>. However, now I have the issue, that those are two different types, and I don't get access to the private members. So, I either need to make more stuff public than I want to, or find a different way of doing this.
How would you implement such a thing?
The full Code
#include <cassert>
#include <utility>
#include <complex>
#include <vector>
#include <algorithm>
#include <iostream>
#include <boost/operators.hpp>
typedef double Real;
typedef std::complex<Real> Complex;
template<typename T>
class Matrix : boost::addable<Matrix<T>>
{
public:
Matrix() = default;
template<typename U>
Matrix(const Matrix<U> &other)
: m_(other.m()), n_(other.n()),
data_(other.data_.begin(), other.data_.end()) { }
Matrix(size_t m, size_t n) : m_(m), n_(n), data_(m*n) { }
Matrix(size_t m, size_t n, const T &initial)
: m_(m), n_(n), data_(m*n, initial) { }
size_t m() const { return m_; }
size_t n() const { return n_; }
size_t size() const {
assert(m_*n_ == data_.size());
return data_.size();
}
const T &operator()(size_t i, size_t j) const { return data_[i*m_ + j]; }
T &operator()(size_t i, size_t j) { return data_[i*m_ + j]; }
void fill(const T &value) {
std::fill(data_.begin(), data_.end(), value);
}
Matrix &operator+=(const Matrix &other) {
assert(dim_match(other));
for (int i = 0; i < size(); ++i) {
data_[i] += other.data_[i];
}
return *this;
}
friend std::ostream &operator<<(std::ostream &o, const Matrix &m) {
if (m.size() == 0) {
o << "()" << std::endl;
return o;
}
for (int i = 0; i < m.m(); ++i) {
o << "( ";
for (int j = 0; j < m.n() - 1; ++j) {
o << m(i,j) << ", ";
}
o << m(i, m.n() - 1) << " )" << std::endl;
}
return o;
}
private:
bool dim_match(const Matrix &other) {
return n_ == other.n_ && m_ == other.m_;
}
private:
int m_, n_;
typedef std::vector<T> Store;
Store data_;
};
int main() {
Matrix<Real> A(2,3, 1.);
Matrix<Complex> B(2,3, Complex(0,1));
auto C = Matrix<Complex>(A) + B;
std::cout << A << std::endl;
std::cout << B << std::endl;
std::cout << C << std::endl;
}
This is how I'd do it: use a friend template function (see Operator overloading: The Decision between Member and Non-member):
template<typename T>
class Matrix
{
public:
template<typename> friend class Matrix;
And then later
template <typename T1, typename T2>
Matrix<typename std::common_type<T1, T2>::type>
operator+(Matrix<T1> const& a, Matrix<T2> const& b)
{
Matrix<typename std::common_type<T1, T2>::type> result(a);
return (result += b);
}
Note the use of common_type to arrive at a sensible resulting type (you might want to introduce your own trait there to cater for your specific requirements)
See it Live On Coliru