    #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) {
    	const auto& data = pol.data;
    	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) ? "" : "+";
    	}; 
    	// RELY ON UNSIGNED OVERFLOW FOR THE LOOP CONDITION !!!
        for (size_t i = pol.data.size()-1; i < pol.data.size(); i-- ) {
            o << sign(i) << pol.data[i] << power(i); 
        }
        return o;
    }
//
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;
    }
    
    int main() { 
      using Matrix = Matrix<Polynomial<double>>;
      Polynomial<double> p1{{1,2}};
      Matrix mp(2,3,p1);
      std::cout << mp;
      return 0;
    }