Błąd kompilacji. Szablon klasy macierzy.

0

Witam,
Od 2h walczę z błędem kompilacji klasy macierzy.
Błędy które wyrzuca kompilator:

 
Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2001	unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class CMatrix<int> const &)" (??6@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV01@AEBV?$CMatrix@H@@@Z)	Macierze	C:\Users\bujaz\Desktop\Programowanie\C++\Klasy\Macierze\Macierze\main.obj	1	

Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2001	unresolved external symbol "public: __cdecl CMatrix<int>::~CMatrix<int>(void)" (??1?$CMatrix@H@@QEAA@XZ)	Macierze	C:\Users\bujaz\Desktop\Programowanie\C++\Klasy\Macierze\Macierze\main.obj	1	

Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2001	unresolved external symbol "public: __cdecl CMatrix<int>::CMatrix<int>(unsigned int,unsigned int)" (??0?$CMatrix@H@@QEAA@II@Z)	Macierze	C:\Users\bujaz\Desktop\Programowanie\C++\Klasy\Macierze\Macierze\main.obj	1	

main.cpp

 
#include "Matrix.h"
#include <iostream>

using namespace std;

int main()
{
	int x, y;
	cout << "Rozmiar macierzy: ";
	cin >> x >> y;

	CMatrix< int > A(x, y);
	std::cout << A;

	std::cin.get();
	std::cin.get();

	return 0;
}

Matrix.cpp

#include "Matrix.h"
#include <cmath>
#include <cassert>

template <typename T>
CMatrix<T>::CMatrix(unsigned int row, unsigned int col) : rows(row), columns(col)
{
	matrix.resize(row);

	for (unsigned i = 0; i < row; i++)
	{
		matrix[i].resize(columns);
	}
}

template <typename T>
CMatrix<T>::CMatrix(const CMatrix<T> & m)
	: rows{ m.getRows()}, columns { m.getColumns()}
{
	matrix.resize(rows);
	for (unsigned i = 0; i < rows; i++)
	{
		matrix[i].resize(columns);
	}

	for (unsigned i = 0; i < m.getRows(); ++i)
    {
        for (unsigned j = 0; j < m.getColumns(); ++j)
        {
            setValue(i, j, m.getValue(i, j));
        }
    }
}

template <typename T>
CMatrix<T> & CMatrix<T>::operator=(const CMatrix<T> & m)
{
	return CMatrix<T>(m);
}

/*template <typename T>
CMatrix<T>::CMatrix(CMatrix<T> && m) : rows{ m.getRows() }, columns{ m.getColumns() }, matrix{m.matrix}
{
	m.rows = 0;
	m.columns = 0;
	m.matrix.clear();
}*/

/*CMatrix & CMatrix::operator=(CMatrix && m)
{
}*/

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


template <typename T>
CMatrix<T> CMatrix<T>::operator*(const T n) const
{
	CMatrix A(rows, columns);

	for (unsigned i = 0; i < rows; i++)
	{
		for (unsigned j = 0; j < columns; j++)
		{
			A.setValue(i, j, getValue(i, j) * n);
		}
	}

	return A;
}

template <typename T>
CMatrix<T> CMatrix<T>::operator*(const CMatrix<T> & A) const
{
	///Działanie jest nie wykonalne gdy liczba kolumn pierwszej macierzy jest różna od liczby wierszy drugiej macierzy.
	if (!(columns == A.rows))
	{
		//assert(columns != A.rows, "Nie można mnożyć tych macieży!");
		throw;
	}

	CMatrix<T> C(rows, columns);

	for (unsigned i = 0; i < rows; i++)
	{
		for (unsigned j = 0; j < columns; j++)
		{
			double add = 0.0;
			for (unsigned k = 0; k < A.rows; ++k)
			{
				add += getValue(i, k) * A.getValue(k, j);
			}
			C.setValue(i, j, add);
		}
	}

	///Pamiętaj aby używać delete C; !!!
	return C;
}

template <typename T>
CMatrix<T> CMatrix<T>::operator+(const CMatrix<T> & A) const
{
	if (!(rows == A.rows && columns == A.columns))
	{
		std::cout << "Blad\n\tNie mozna dodac tych macierzy!\n";
		return CMatrix<T>(0, 0);
	}

	CMatrix<T> B(rows, columns);

	for (unsigned i = 0; i < rows; i++)
	{
		for (unsigned j = 0; j < columns; j++)
		{
			B.setValue(i, j, getValue(i, j) + A.getValue(i, j));
		}
	}

	return B;
}

template <typename T>
CMatrix<T> CMatrix<T>::operator-(const CMatrix<T> & A) const
{
	if (!(rows == A.rows && columns == A.columns))
	{
		std::cout << "Blad\n\tNie mozna dodac tych macierzy!\n";
		return CMatrix<T>(rows, columns);
	}

	CMatrix<T> B(rows, columns);

	for (unsigned i = 0; i < rows; i++)
	{
		for (unsigned j = 0; j < columns; j++)
		{
			B.setValue(i, j, getValue(i, j) - A.getValue(i, j));
		}
	}

	return B;
}

template <typename T>
CMatrix<T> CMatrix<T>::transposition() const
{
	CMatrix B(columns, rows);

	for (unsigned i = 0; i < rows; i++)
	{
		for (unsigned j = 0; j < columns; j++)
		{
			B.setValue(j, i, getValue(i, j));
		}
	}

	return B;
}

template <typename T>
CMatrix<T> CMatrix<T>::reverse() const
{
	double x = getDet();

	if (x == 0.0) throw;

	x = 1.0 / x;

	return CMatrix<T>( x * this->algebraicCoplement().transposition());
}

template <typename T>
T CMatrix<T>::getValue(unsigned row, unsigned col) const
{
	if (row >= getRows() || col >= getColumns())
	{
		std::cerr << "\n\n\tPrzekroczono tablice vector!\n\n";
		throw;
	}

	return matrix[row][col];
}

template <typename T>
void CMatrix<T>::setValue(unsigned row, unsigned col, T val)
{
	if (!(row < rows && col < columns))
	{
		std::cout << "Error!\n\tPrzekroczono zasieg!\n";
		throw;
		return;
	}

	matrix[row][col] = val;

	return;
}

template <typename T>
T CMatrix<T>::getDet() const
{
	if (rows != columns)
	{
		std::cerr << "\n\nBlad! Macierz nie jest kwadraowa... \tNie mozna obliczyc wyznacznika!\n\n";
		return 0.0;
	}

	return det(*this);
}

template <typename T>
T CMatrix<T>::det(CMatrix<T> m) const
{
	if (m.getColumns() != m.getRows()) throw;

	if (m.getRows() == 2)
		return ((matrix[0][0] * matrix[1][1]) - (matrix[0][1] * matrix[1][0]));
	else if (m.getColumns() == 1) return matrix[0][0];

    T ret = 0.0;

	for (unsigned i = 0; i < rows; i++)
	{
		int x = ( (0 + i % 2) == 0 ) ? 1 : -1;
		ret += matrix[0][i] * static_cast<double>(x) * removeRowAndCol(0, i).getDet();
	}

	return ret;
}

template <typename T>
CMatrix<T> CMatrix<T>::removeRowAndCol(unsigned int row, unsigned int col) const
{
	if (row >= getRows() || col >= getColumns()) throw;

	CMatrix<T> ret(getRows() - 1, getColumns() - 1);

	unsigned plus_k = 0;
	unsigned plus_l = 0;

	for (unsigned k = 0; k < ret.getRows(); k++)
	{
		if (k == row) plus_k = 1;

		for (unsigned l = 0; l < ret.getColumns(); l++)
		{
			if (l == col) plus_l = 1;
			ret.setValue(k, l, getValue(k + plus_k, l + plus_l));
		}
		plus_l = 0;
	}

	return ret;
}
template <typename T>
CMatrix<T> CMatrix<T>::algebraicCoplement() const
{
	CMatrix<T> ret(this->getRows(), this->getColumns());

	for (unsigned i = 0; i < ret.getRows(); ++i)
	{
		for (unsigned j = 0; j < ret.getColumns(); ++j)
		{
			ret.setValue(i, j, pow(-1, i+j) * this->removeRowAndCol(i, j).getDet());
		}
	}

	return ret;
}

template <typename T>
CMatrix<T> operator*(const T n, const CMatrix<T> & A)
{
	return A * n;
}

///Friends
template <typename T>
std::ostream& operator<<(std::ostream &out, const CMatrix<T> & A)
{
	out << "row: " << A.rows << " col: " << A.columns << std::endl;
	for (unsigned i = 0; i < A.rows; i++)
	{
		out << "| ";
		for (unsigned j = 0; j < A.columns; j++)
		{
			out.width(5);
			out.fill('*');
			out << A.getValue(i, j) << " ";
		}
		out << "|\n";
	}

	return out;
}

template <typename T>
std::istream & operator>>(std::istream & in, CMatrix<T> & A)
{
	std::cout << "\n\n\tPodaj wartosc macierzy\n";

	for (unsigned i = 0; i < A.getRows(); i++)
	{
		for (unsigned j = 0; j < A.getColumns(); j++)
		{
			int value;

			do
			{
				std::cout << "\ta( " << i << ", " << j << " ) = ";

			} while (!(in >> value));

			A.setValue(i, j, value);
		}
	}
	return in;
}

Matrix.h

 
#pragma once

#include <vector>
#include <initializer_list>
#include <iostream>

template <typename T>
class CMatrix
{
public:
	/************************Konstruktory**********************************/
	CMatrix(unsigned int row, unsigned int col);
	CMatrix(const CMatrix<T> & m);
	CMatrix<T> & operator=(const CMatrix<T> & m);
	~CMatrix();

	/************************Friendzone! ;(********************************/
	friend CMatrix<T> operator*(const T n, const CMatrix<T> & A);
	friend std::ostream & operator<<(std::ostream & out, const CMatrix<T> & A);
	friend std::istream & operator>>(std::istream & in, CMatrix<T> & A);

	/***************************Operatory**********************************/

	CMatrix<T> operator*(const T n) const;
	CMatrix<T> operator*(const CMatrix<T> & A) const;
	CMatrix<T> operator+(const CMatrix<T> & A) const;
	CMatrix<T> operator-(const CMatrix<T> & A) const;

	CMatrix<T> transposition() const;
	CMatrix<T> reverse() const;
	CMatrix<T> algebraicCoplement() const;

	/*************************Funkcje*************************************/

	inline unsigned int getRows() const { return rows; }
	inline unsigned int getColumns() const { return columns; }
	T getValue(unsigned row, unsigned col) const;
	void setValue(unsigned row, unsigned col, T val);
	T getDet() const;

private:
	const unsigned int rows;
	const unsigned int columns;
	std::vector<std::vector<T> > matrix;

	T det(CMatrix m) const;
	CMatrix removeRowAndCol(unsigned int row, unsigned int col) const;
};

Z góry dziękuje :)

0

Zacznij od dodania

#include <iosfwd>

do Macierz.h (Matrix.h ?)
Dodaj deklarac ję funkcji zaprzyjaznionych przed klasę.

0
 
...
};

template<typename T>
friend CMatrix<T> operator*(const T n, const CMatrix<T> & A);
template<typename T>
friend std::ostream & operator<<(std::ostream & out, const CMatrix<T> & A);
template<typename T>
friend std::istream & operator>>(std::istream & in, CMatrix<T> & A);

O coś takiego chodzi? To się nie kompiluje.

2

Nie.

Dobra może tak w vs zadziała.

// w klasie CMatric
    template <typename S>
    friend CMatrix<S> operator*(const T n, const CMatrix<S> & A);
    template <typename S>
    friend std::ostream & operator<<(std::ostream & out, const CMatrix<S> & A);
    template <typename S>
    friend std::istream & operator>>(std::istream & in, CMatrix<S> & A);

albo

// w klasie CMatric
    friend CMatrix<T> operator* <>(const T n, const CMatrix<T> & A);
    friend std::ostream & operator<< <>(std::ostream & out, const CMatrix<T> & A);
    friend std::istream & operator>> <>(std::istream & in, CMatrix<T> & A);

Jak nie to kopiujesz to przed klasę bez friend, a jeszcze wczesniej forward deklaracja klasy.

Generalnie użyłeś parametru T z klasy CMatrix, podczas gdy te funkcje nie naleza do tej klasy. Jednocześnie nie jest specjalizacja

3

A tak swoja droga czemu masz klase templetowa w pliku cpp? Jak myslsiz gdzie zostanie zinstancjalizowana?

3

https://isocpp.org/wiki/faq/templates - lektura na dzisiaj

0

Kurcze, teraz lepiej. Tylko nie bardzo wiem dlaczego? Został tylko jeden błąd:

Severity	Code	Description	Project	File	Line	Suppression State
Error	LNK2001	unresolved external symbol "class std::basic_ostream<char,struct std::char_traits<char> > & __cdecl operator<<(class std::basic_ostream<char,struct std::char_traits<char> > &,class CMatrix<int> const &)" (??6@YAAEAV?$basic_ostream@DU?$char_traits@D@std@@@std@@AEAV01@AEBV?$CMatrix@H@@@Z)	Macierze	C:\Users\bujaz\Desktop\Programowanie\C++\Klasy\Macierze\Macierze\main.obj	1	
0

Super, jak działa to przeczytaj linka ktorego dali Ci wyzej na przyszłość.