1

I have a polynomial of the type std::vector<T> and a matrix of the type std::vector<std::vector<T>>, with classes for both of them. The output (in my case void print()-function) for each of those classes works fine. Now I created a matrix consisting of multiple polynomials, like this, and I'm not entirely sure how to create an output for it.

Suppose I have a polynomial p1: Polynomial<T> p1{0,1,2}. My Polynomial::print function interprets it correctly and returns: x^2+x+1. For a 'normal' matrix of the type Matrix<T> m1(2,2,0), a 2x2-matrix filled with 0's, it is correctly returned with Matrix::print() as well as:

0, 0
0, 0

Now, suppose I want a polynomial matrix m1: Matrix<Polynomial<T>> mp(2,2,p1), a 2x2-matrix filled polynomial p1 from before. The code is accepted, but now I want to print the matrix using matrix::print(), so that I get:

x^2+x+1, x^2+x+1
x^2+x+1, x^2+x+1

Minimal working example:

#include<iostream>
#include<vector>

using namespace std;

template <typename T>
class Polynomial;

template <typename T>
class Matrix
{
public:
  Matrix(std::vector<std::vector<T> > ma);
  Matrix(int rows, int cols, T const & init);
  Matrix(const Matrix & m);
  ~Matrix();
  Matrix ();
  void print();
  friend void Polynomial<T>::print();

private:
  std::vector<std::vector<T>> Ma;
};

template <typename T>
Matrix<T>::Matrix(std::vector<std::vector<T>> ma)
  :Ma(ma)
  {}

template <typename T>
Matrix<T>::Matrix(int rows, int cols, T const & init)
{
  std::vector<std::vector<T>> b(rows, std::vector<T>(cols, init));
  Ma=b;
}

template <typename T>
Matrix<T>::~Matrix()
  {}

template <typename T>
Matrix<T>::Matrix() :
Matrix(1,1,0)
{}

template <typename T>
Matrix<T>::Matrix(const Matrix & m)
{
  Ma = m.Ma;
}


template <typename T>
void Matrix<T>::print()
{
  for (auto i = 0; i < Ma.size(); i++)
  {
    for (auto j = 0; j < Ma[i].size(); j++)
      if ( j == Ma.size()-1 )
      {
    cout << Ma[i][j]; //This causes problems
      }
      else
    cout << Ma[i][j] << ", \t";
    cout << endl;
  }
}

template <typename T>
class Polynomial
{
    public:
    Polynomial(std::vector<T> const& coef);
    Polynomial(std::initializer_list<T> const& coef);
    void print();
    const int getdeg();
    const T getKoeff(int index) const;

    friend class Matrix<T>;
    Polynomial ();

    friend void print();

    private:
    std::vector<T> coefficient;

};

template <typename T>
Polynomial<T>::Polynomial(std::vector<T> const& coef) :
    coefficient(coef)
{}

template <typename T>
Polynomial<T>::Polynomial(std::initializer_list<T> const& coef) :
    coefficient(coef)
{}

template <typename T>
Polynomial<T>::Polynomial ()
{
  coefficient = new std::vector<T> [coefficient.getdeg()];
  coefficient[0]=0;
}

template <typename T>
void Polynomial<T>::print() //Reduced version for demonstration purposes, but
{
    for ( int i = getdeg(); i >= 0; i-- )
    {
        cout << coefficient[i] << "x^" << i; //the output is always  of the type cout << xyz
    }
}

template <typename T>
const int Polynomial<T>::getdeg()
{
  int g = coefficient.size()-1;
    return g;
}

int main()
{

 typedef double T;    
  Polynomial<T> p1{0,1,2};
  p1.print();

  Matrix<Polynomial<T>> mp(2, 3, Polynomial<T>{0});
//  mp.print(); //When this is commented out chaos ensues
  return 0;
}

2x^21x^10 is returned (Note: +&- excluded from the notation, since the code would be too long).

The matrix::print() might cause problems due to cout having problems handling the result of the polynomial. Anybody have an idea how to make matrix::print() give useful results for a polynomial matrix? Thank you in advance.

Retze
  • 27
  • 1
  • 5

2 Answers2

1

In Matrix<T>::print() you are trying to call

cout << Ma[i][j];

and when Ma[i][j] is a Polynomial<double>, there is no matching overload for the output operator. You could call Ma[i][j].print() instead, but then your Matrix wont work for int. Long story short: Instead of writing your own print() you better overload operator<<(std::ostream&,const T&) for your types.

For Polynomial that would be something along the line of (I allowed myself to strip your code down quite a bit and to add the "+"):

#include<iostream>
#include<vector>

template <typename T> struct Polynomial { std::vector<T> data; };

template <typename T> 
std::ostream& operator<<(std::ostream& o,const Polynomial<T>& pol) {        
    auto power = [](int n){ 
        return (n==0) ? "" : (n==1) ? "x" : "x^" + std::to_string(n);
    };
    auto sign = [&](int i){ 
        return (pol.data[i]<0 || i==pol.data.size()-1) ? "" : "+";
    }; 
    // DO THIS ONLY AT HOME !!!  --------v        
    for (size_t i = pol.data.size()-1; i < pol.data.size(); i-- ) {
        o << sign(i) << pol.data[i] << power(i); 
    }
    return o;
}

int main() {
    Polynomial<double> p1{{0,1,2,-3,4}};
    std::cout << p1 << "\n";
}

Prints

4x^4-3x^3+2x^2+1x+0

You dont need to write desctructors/constructors that the compiler can write for you. Actually it doesnt need any constructor as long at is just a bare std::vector in disguise. Note that I tried to keep it short, but not necessarily clean, for example I would never rely on unsigned overflow for a loop condition in any serious code, and heavy use of the ternary doesnt really boost readability. However, I am serious about using lambdas. They help to keep stuff localized. I'll leave it to you to print nothing for the last coefficient in case it is 0 ;).

To print rows of the matrix you could provide an overload for std::vector<T>, that would be something along the line of:

template <typename T> struct Matrix {
      using element_type = T;
      using row_type = std::vector<element_type> ;
      using data_type = std::vector<row_type> ;
      Matrix(int rows, int cols, T const & init) : 
          data(data_type(rows,row_type(cols,init)))
      {}
      data_type data;
};

template <typename T> 
std::ostream& operator<<(std::ostream& o,const std::vector<T>& v) {
    for (auto& x : v) o << x << "\t";
    return o;
}

template <typename T> 
std::ostream& operator<<(std::ostream& o,const Matrix<T>& mat) {
    for (const auto& row : mat.data) o << row << "\n";
    return o;
}

Now printing a matrix is as simple as this

int main() { 
    using Matrix = Matrix<Polynomial<double>>;
    Polynomial<double> p1{{1,2}};
    Matrix mp(2,3,p1);
    std::cout << mp;
    return 0;
}

Prints

2x+1 2x+1 2x+1
2x+1 2x+1 2x+1

See also here: https://ideone.com/n00bqn (is ideone trying to make fun of me or what? :)

463035818_is_not_a_number
  • 64,173
  • 8
  • 58
  • 126
  • Wow dude, this is what I call an elegant approach and it works just as fine. Thanks a for your input. – Retze Feb 23 '18 at 09:46
  • 1
    @Retze please take it with a grain of salt (or rather a bag of salt ;). For example only after writing the answer I realized that it would have been nicer to print the rows inside `operator<`. I hope you wont simply copy/paste it, but adapt it to your needs. If anything is unclear, please ask – 463035818_is_not_a_number Feb 23 '18 at 10:26
1

You want to print content of Map[i][j] (it is Polynomial<double>) by using operator<< but operator which takes as argument Polynomial<double> is not defined. So you should add declaration

template<class U>
friend std::ostream& operator<<(std::ostream&,const Polynomial<U>&);

in your Polynomial template and make definition outside class as

template<class T>
std::ostream& operator<<(std::ostream& out, const Polynomial<T>& poly)
{
  poly.print();
  return out;
}

then you can call

cout << Ma[i][j] << ", ";

in your Matrix<T>::print method.

rafix07
  • 17,659
  • 2
  • 14
  • 24
  • Thanks mate. But there still seems to be a problem, when calling Matrix::print(): "In instantiation of 'std::ostream& operator<&) [with T = double; std::ostream = std::basic_ostream]': required from 'void Matrix::print() [with T = Polynom]' – Retze Feb 23 '18 at 09:25
  • 1
    @Retze Ohh my mistake, in `operator< is declared with `const` qualifier, so there are two solutions: you add `const` to `print` method in Polynomial class (for const object you can call only const methods) or you remove const from operator<< -> `operator<& poly)`. Remember that from `print` method you are calling `getdeg` so if `print` will be const, `getdeg` should be too as const. – rafix07 Feb 23 '18 at 09:34