Click here to Skip to main content
15,886,026 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hi, i'm just playing around with templates and i'm trying to add two 2D arrays as stated in title...please help how should i change my code to make it work...code shown below...
C++
template <typename Left, typename Right>
class sum
{
private:
    Left *myleft;
    Right *myright;
public:
    sum(Left *l, Right *r) : myleft(l), myright(r) {}

    class Inner
    {
    private:
        Left _myleft;
        Right _myright;
    public:
        Inner(Left l, Right r) : _myleft(l), _myright(r) {}
        double operator[](int j)
        {
            return (_myleft[j]+_myright[j]);
        }
    };

    Inner operator[](int i)
    {
        return Inner(myleft[i]+myright[i]);
    }
};

class array
{
private:
    double** data;
    int N, M;
public:
    array( double **_data, int _N, int _M) :data(_data), N(_N), M(_M) { }

    class Proxy
    {
    private:
        double* _data;
    public:
        Proxy(double* __data) : _data(__data) { }
        double operator[](int j)
        {
            return _data[j];
        }
    };

    template <typename Left,typename Right>
    void operator=(sum<Left,Right> expr)
    {
        for(int i=0; i<N; ++i)
            for(int j=0; i<M; ++j)
                data[i][j] = expr[i][j];
    }

    Proxy operator[](int i)
    {
        return Proxy(data[i]);
    }
};

template <typename Left>
sum<Left, array> operator+( Left a, array b)
{
    return sum<Left, array>(a,b);
}

int main()
{
    double **test;
    test = new double*[5];
    for(int i=0; i<5; ++i){
        test[i] = new double[4];
        for(int j=0; j<4; ++j){
            test[i][j] = 1.0;
        }
    }

    array a(test,5,4), b(test,5,4), c(test,5,4);

    c = sum<array,array>(a,b);  // <<----error here

    for(int i=0; i<5; ++i){
        cout<<"\n";
        for(int j=0; j<4; ++j){
            cout<<c[i][j]<<" ";
        }
    }
}
Posted

I would not use pointers to elements but rather define the Matrix using numeric template parameters. E.g.
C++
template<typename TElem, size_t R, size_t C=R>
class Matrix
{
  ...
};
Then define internally to that class some types and the data storage, e.g.
C++
...
public:
  typedef TElem ElementType;
  typedef ElementType RowType[C];
  typedef RowType MatrixType[R];
private:
  MatrixType _matrix;
...
Followed by some constructors for that class, e.g.
C++
...
public:
  Matrix()
  {
    for(size_t i = 0; i < R; ++i) for(int j = 0; j < C; ++j) _matrix[i][j] = 0;
  }
  Matrix(const MatrixType &matrix)
  {
    for(size_t i = 0; i < R; ++i) for(int j = 0; j < C; ++j) _matrix[i][j] = matrix[i][j];
  }
...
Finally implement the adding and some print facility within that class, e.g.
C++
 ...
Matrix& addAssign(const Matrix& rhs)
{
  for(size_t i = 0; i < R; ++i) for(int j = 0; j < C; ++j) _matrix[i][j] += rhs._matrix[i][j];
  return *this;
}

void print(ostream& out, const string& name) const
{
  out << "### " << name << " ###" << endl;
  for(size_t i = 0; i < R; ++i)
  {
    for(int j = 0; j < C; ++j)
    {
      if (j > 0) out << ",";
      out << _matrix[i][j];
    }
    out << endl;
  }
}
...
Note that I implemented in-place adding, i.e. the matrix gets modified by adding the rhs elements to the own elements.

Using:
C++
typedef Matrix<double,2,3> M23;
M23 a;
M23 b(a);
M23::MatrixType m = {{1,0,0},{0,1,0}};
M23 c(m);
a.print(cout, "a");
b.print(cout, "b");
c.print(cout, "c");
c.addAssign(c);
c.print(cout, "c");

Result:
### a ###
0,0,0
0,0,0
### b ###
0,0,0
0,0,0
### c ###
1,0,0
0,1,0
### c ###
2,0,0
0,2,0
Cheers
Andi
 
Share this answer
 
v3
Comments
Daniel Pfeffer 2-Mar-15 2:46am    
The only modification that I would make would be to overload the '+=' and '+' operators to perform the matrix addition.
You have a few issues, for one the constructor of sum takes pointers to Left and Right but when used, pointers are not being passed.

I think the problem becomes simpler to look at if the internal classes are broken out;
C++
#include<iostream>

using namespace std;

/* represents a one-dimensional array */
template<typename T> class row {
private:
    T* data;
    size_t n;
public:
    row(T* data, size_t n)
        : data(data), n(n) {
    }

    T operator[](int i) {
        return data[i];
    }
};

/* represents a two-dimensional array */
template<typename T> class array {
private:
    T** data;
    size_t n, m;
public:
    array(T** data, size_t n, size_t m)
        : data(data), n(n), m(m) {
    }

    row<T> operator[](int i) {
        return row<T>(data[i], m);
    }
};

/* represents a two rows from two arrays, observable as a single summed row */
template<typename T> class sum_row_proxy {
private:
    row<T> left;
    row<T> right;
public:
    sum_row_proxy(row<T> left, row<T> right)
        : left(left), right(right) {
    }

    T operator[](int i) {
        return left[i] + right[i];
    }
};

template<typename T> class sum {
private:
    array<T> left;
    array<T> right;
public:
    sum(const array<T>& left, const array<T>& right)
        : left(left), right(right) {
    }

    sum_row_proxy<T> operator[](int i) {
        return sum_row_proxy<T>(left[i], right[i]);
    }
};

int main() {
    double **test = new double*[5];
    for(int i = 0; i < 5; ++i) {
        test[i] = new double[4];
        for(int j = 0; j < 4; ++j) {
            test[i][j] = 1.0;
        }
    }

    array<double> array_a(test, 5, 4);
    array<double> array_b(test, 5, 4);

    sum<double> s(array_a, array_b);

    for(int i=0; i<5; ++i){
        cout<<"\n";
        for(int j=0; j<4; ++j){
            cout<<s[i][j]<<" ";
        }
    }

    return 0;
}



I've tried to use (roughly) the same classes you used, but this problem can also be solved by a single class (plus a proxy class for the second indexer) taking two T** as input.

Hope this helps,
Fredrik
 
Share this answer
 
I would not declare a template class, but a template function. And would design the function with three arguments for: left operand, right operand, and result. If you don't use a result argument, you will have to pass the result as the return value of your function. That, however, is not what you want. If the return value would also be a pointer to an array, the function would have to allocate that array. And the calling code would have to free the array.

So: I would go for something like:
template<typename t="">
void sum2D (T* pLeft, T* pRight, T* pSum, int cols, int rows)
{
   int n = cols * rows;
   for (int i = 0; i < n; ++i)
      pSum[i] = pLeft[i] + pRight[i};
};
</typename>

Note that now the caller has to allocate the space for the result array.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900