I have a big problem in my C++ Code example. There is something wrong with 'friend' and the 'template'.
Error Messages:
Matrix.h:26:79: warning:
friend declaration 'std::ostream&
matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: note:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77: warning:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const
matrixClass::Matrix&)' declares a non-template function
[-Wnon-template-friend]
friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
Matrix.cpp:1:0:
C:\Users\Peter\CLionProjects\PK\untitled76\Matrix.h:26:79: warning:
friend declaration 'std::ostream&
matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: note:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77: warning:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const
matrixClass::Matrix&)' declares a non-template function
[-Wnon-template-friend]
friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
CMakeFiles\untitled76.dir/objects.a(main.cpp.obj): In function `main':
main.cpp:8: undefined reference to
main.cpp:8: undefined reference to matrixClass::Matrix<int>::Matrix(int)'<br>
main.cpp:10: undefined reference tomatrixClass::Matrix::set(int, int, int)'
main.cpp:11: undefined reference to matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:12: undefined reference tomatrixClass::Matrix::set(int, int, int)'
main.cpp:13: undefined reference to matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:15: undefined reference tomatrixClass::operator<<(std::ostream&, matrixClass::Matrix const&)'
main.cpp:15: undefined reference to matrixClass::operator<<(std::ostream&, matrixClass::Matrix<int> const&)'<br>
main.cpp:8: undefined reference tomatrixClass::Matrix::~Matrix()'
main.cpp:8: undefined reference to `matrixClass::Matrix::~Matrix()'
Code:
Matrix.h
#ifndef MATRIX_H_
#define MATRIX_H_
#include <iostream>
namespace matrixClass {
template<class T>
class Matrix {
private:
int dimension;
T **m;
public:
Matrix(int d);
Matrix(const Matrix &original);
~Matrix();
void set(int x, int y, T value);
T get(int x, int y) const;
int getDimension() const;
friend std::ostream &operator<<(std::ostream&, const Matrix<T> &matrix);
friend Matrix<T>* operator*(const Matrix<T> &m1, const Matrix<T> &m2);
};
}
#endif
Matrix.cpp
#include "Matrix.h"
using namespace matrixClass;
template<class T>
Matrix<T>::Matrix(int d)
: dimension{d}, m{new T *[d]} {
//m = new T*[d];
for (int i = 0; i < d; i++) {
m[i] = new T[d];
}
}
// COPY-CONSTRUCTOR
template<class T>
Matrix<T>::Matrix(const Matrix &original)
: dimension{original.dimension},
m{new T *[original.dimension]} {
for (int i = 0; i < dimension; i++) {
*(m + i) = *(original.m + i);
}
}
// DESTRUCTOR
template<class T>
Matrix<T>::~Matrix() {
for (int i = 0; i < dimension; i++) {
delete[] m[i];
}
delete[] m;
}
template<class T>
void Matrix<T>::set(int x, int y, T value) {
m[x][y] = value;
}
template<class T>
T Matrix<T>::get(int x, int y) const {
return m[x][y];
}
template<class T>
int Matrix<T>::getDimension() const {
return dimension;
}
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2) {
int dimension = m1.getDimension();
Matrix<T>* m = new Matrix<T>(dimension);
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
T value = 0;
for(int i = 0; i < dimension; i++) {
value += m1.get(x, i) * m2.get(i, y);
}
m->set(x, y, value);
}
}
return m;
}
main.cpp
#include <iostream>
#include "Matrix.h"
using namespace matrixClass;
using namespace std;
int main() {
Matrix<int> m(2);
m.set(0, 0, 1);
m.set(0, 1, 2);
m.set(1, 0, 3);
m.set(1, 1, 4);
cout << m << "*" << endl << m << "=" << endl;
return 0;
}
In friend declaration operator<< refers to a non-template function, while its definition says it's a template function; they don't match.
You can define it inline with the friend declaration (as non-template function):
template<class T>
class Matrix {
... ...
friend std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
... ...
};
Or make the friend declaration referring to the function template:
// class declaration
template<class T>
class Matrix;
// function declaration
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
// class definition
template<class T>
class Matrix {
... ...
friend std::ostream& operator<< <T>(std::ostream& output, const Matrix<T>& matrix);
... ...
};
// function definition
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
And about the undefined reference error, see Why can templates only be implemented in the header file?
This answer addresses the problem with your non-member operator<<() and operator*() using Friend Templates, which is slightly different from making an instance of a function template a friend (the second solution presented by #songyuanyao). The difference is that with a Friend Template, all instances of the template function are friends of the class Matrix<>. In this case, I don't think there is any practical difference, but in others, there may be. Therefore, I figured I'd present it anyway.
I think about it like this. Both operators are non-member functions which means they are independent from the class Matrix<>, so think of their prototypes independently:
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2);
Now, replace T with U because to make all instances of them friends of Matrix<>, their prototype needs to be included in the class definition for Matrix<> which is also a template, and it is already using T as its template parameter.
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2);
Now, you can make them friends of Matrix<>. All you need is the appropriate syntax:
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
Finally, they all need to be within the matrixClass namespace, and their declarations and definitions need to be in the right order so that everyone know the others exists:
namespace matrixClass {
// BEGIN Forward declarations
template<class T>
class Matrix;
template<class U>
std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
// END Forward declarations
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
...
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix)
{
... // your implementation goes here
}
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2)
{
... // your implementation goes here
}
} // end of namespace matrixClass
All this template code should be in the header file, Matrix.h, as it has already been mentioned.
Also, I think that you should change the prototype of operator*() to return Matrix<U> instead of Matrix<U>*. It will behave more like the normal operator*(), and it'll enable you to do things like: Matrix<int> m = m1*m2; or m = m1*m2*m3;. Additionally, the users of your class won't have to worry about deleting the memory allocated by operator*() or the performance cost of the dynamic allocation. Just create a local Matrix<U> variable in operator*() and return it by value; let Return Value Optimization (RVO) take care of the rest.
Related
I've been stuck on this code for a while and can't get it to compile, what exactly am I doing wrong? If there are bugs present when it compiles, please ignore them as I can fix that on my own. As of right now I'm just trying to get it to run. Thank you in advance.
#include <iostream>
#include <string.h>
//template <class t> class Matrix; //possible way of fixing the friend function.
using namespace std;
template<class T, size_t NROWS, size_t NCOLS>
std::ostream & operator<<(std::ostream &os, const Matrix<T,NROWS, NCOLS> &matrix);
template<class T, size_t NROWS = 1, size_t NCOLS = 1>
class Matrix{
public:
Matrix(){}
friend std::ostream &operator<< <>(std::ostream&os,const Matrix<T, NROWS, NCOLS> &matrix);
private:
T container[NROWS][NCOLS];
};
template<class T,size_t NROWS, size_t NCOLS>
std::ostream &operator<<(std::ostream &os,const Matrix<T,NROWS,NCOLS>&matrix){
for(size_t i=0;i<NROWS;++i){
for(size_t j=0;j<NCOLS;++j){
os <<matrix.container[i][j]<<" ";
}
os <<std::endl;
}
os <<std::endl;
}
int main(){
Matrix<float, 10, 5> mat;
cout << mat;
return 0;
}
The errors from the IDE I use are as follows:
main.cpp:8:51: error: no template named 'Matrix'
std::ostream & operator<<(std::ostream &os, const Matrix &matrix);
main.cpp:15:24: error: no function template matches function template specialization 'operator<<' friend std::ostream &operator<< <>(std::ostream&os,const Matrix &matrix);
main.cpp:35:32: note: in instantiation of template class 'Matrix' requested here Matrix mat;
If you uncomment out line 4, and change it as follows, the code you have compiles:
template <class t, size_t, size_t> class Matrix; //possible way of fixing the friend function.
It seems your problem is that the forward-declared Matrix template parameters don't match the Matrix definition that comes later.
Also, although the code will compile after this fix, there is still a warning which you probably also want to fix:
In function 'std::ostream& operator<<(std::ostream&, const Matrix<T, NROWS, NCOLS>&)':
31:1: warning: no return statement in function returning non-void [-Wreturn-type]
#include <cstddef>
#include <iostream>
template<typename, std::size_t, std::size_t> class Matrix;
template<typename T, std::size_t NROWS, std::size_t NCOLS>
std::ostream& operator<<(std::ostream &os, Matrix<T, NROWS, NCOLS> const &matrix)
{
for (std::size_t row{}; row < NROWS; ++row, os.put('\n'))
for (std::size_t col{}; col < NCOLS; ++col)
os << matrix.container[row][col] << ' ';
return os.put('\n');
}
template<typename T, std::size_t NROWS = 1, std::size_t NCOLS = 1>
class Matrix {
T container[NROWS][NCOLS] = {};
friend std::ostream& operator<< <>(std::ostream&, Matrix<T, NROWS, NCOLS> const&);
};
int main()
{
Matrix<float, 10, 5> mat;
std::cout << mat;
}
Please get rid of the C header <string.h>.
You need to define Matrix before it's usage:
template<class T, size_t NROWS = 1, size_t NCOLS = 1>
class Matrix;
and add a return statement to operator<<, that returns os. You also do not need duplication of operator<< declaration, you can declare it only in a class body.
I have a big problem in my C++ Code example. There is something wrong with 'friend' and the 'template'.
Error Messages:
Matrix.h:26:79: warning:
friend declaration 'std::ostream&
matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: note:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77: warning:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const
matrixClass::Matrix&)' declares a non-template function
[-Wnon-template-friend]
friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
Matrix.cpp:1:0:
C:\Users\Peter\CLionProjects\PK\untitled76\Matrix.h:26:79: warning:
friend declaration 'std::ostream&
matrixClass::operator<<(std::ostream&, const matrixClass::Matrix&)'
declares a non-template function [-Wnon-template-friend]
friend std::ostream &operator<<(std::ostream&, const Matrix &matrix);
Matrix.h:26:79: note:
(if this is not what you intended, make sure the function template
has already been declared and add <> after the function name here)
Matrix.h:28:77: warning:
friend declaration 'matrixClass::Matrix<T>*
matrixClass::operator*(const matrixClass::Matrix&, const
matrixClass::Matrix&)' declares a non-template function
[-Wnon-template-friend]
friend Matrix* operator*(const Matrix &m1, const Matrix &m2);
CMakeFiles\untitled76.dir/objects.a(main.cpp.obj): In function `main':
main.cpp:8: undefined reference to
main.cpp:8: undefined reference to matrixClass::Matrix<int>::Matrix(int)'<br>
main.cpp:10: undefined reference tomatrixClass::Matrix::set(int, int, int)'
main.cpp:11: undefined reference to matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:12: undefined reference tomatrixClass::Matrix::set(int, int, int)'
main.cpp:13: undefined reference to matrixClass::Matrix<int>::set(int, int, int)'<br>
main.cpp:15: undefined reference tomatrixClass::operator<<(std::ostream&, matrixClass::Matrix const&)'
main.cpp:15: undefined reference to matrixClass::operator<<(std::ostream&, matrixClass::Matrix<int> const&)'<br>
main.cpp:8: undefined reference tomatrixClass::Matrix::~Matrix()'
main.cpp:8: undefined reference to `matrixClass::Matrix::~Matrix()'
Code:
Matrix.h
#ifndef MATRIX_H_
#define MATRIX_H_
#include <iostream>
namespace matrixClass {
template<class T>
class Matrix {
private:
int dimension;
T **m;
public:
Matrix(int d);
Matrix(const Matrix &original);
~Matrix();
void set(int x, int y, T value);
T get(int x, int y) const;
int getDimension() const;
friend std::ostream &operator<<(std::ostream&, const Matrix<T> &matrix);
friend Matrix<T>* operator*(const Matrix<T> &m1, const Matrix<T> &m2);
};
}
#endif
Matrix.cpp
#include "Matrix.h"
using namespace matrixClass;
template<class T>
Matrix<T>::Matrix(int d)
: dimension{d}, m{new T *[d]} {
//m = new T*[d];
for (int i = 0; i < d; i++) {
m[i] = new T[d];
}
}
// COPY-CONSTRUCTOR
template<class T>
Matrix<T>::Matrix(const Matrix &original)
: dimension{original.dimension},
m{new T *[original.dimension]} {
for (int i = 0; i < dimension; i++) {
*(m + i) = *(original.m + i);
}
}
// DESTRUCTOR
template<class T>
Matrix<T>::~Matrix() {
for (int i = 0; i < dimension; i++) {
delete[] m[i];
}
delete[] m;
}
template<class T>
void Matrix<T>::set(int x, int y, T value) {
m[x][y] = value;
}
template<class T>
T Matrix<T>::get(int x, int y) const {
return m[x][y];
}
template<class T>
int Matrix<T>::getDimension() const {
return dimension;
}
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2) {
int dimension = m1.getDimension();
Matrix<T>* m = new Matrix<T>(dimension);
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
T value = 0;
for(int i = 0; i < dimension; i++) {
value += m1.get(x, i) * m2.get(i, y);
}
m->set(x, y, value);
}
}
return m;
}
main.cpp
#include <iostream>
#include "Matrix.h"
using namespace matrixClass;
using namespace std;
int main() {
Matrix<int> m(2);
m.set(0, 0, 1);
m.set(0, 1, 2);
m.set(1, 0, 3);
m.set(1, 1, 4);
cout << m << "*" << endl << m << "=" << endl;
return 0;
}
In friend declaration operator<< refers to a non-template function, while its definition says it's a template function; they don't match.
You can define it inline with the friend declaration (as non-template function):
template<class T>
class Matrix {
... ...
friend std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
... ...
};
Or make the friend declaration referring to the function template:
// class declaration
template<class T>
class Matrix;
// function declaration
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
// class definition
template<class T>
class Matrix {
... ...
friend std::ostream& operator<< <T>(std::ostream& output, const Matrix<T>& matrix);
... ...
};
// function definition
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix) {
int dimension = matrix.getDimension();
for(int x = 0; x < dimension; x++) {
for(int y = 0; y < dimension; y++) {
output << matrix.get(x, y) << " ";
}
return output;
}
}
And about the undefined reference error, see Why can templates only be implemented in the header file?
This answer addresses the problem with your non-member operator<<() and operator*() using Friend Templates, which is slightly different from making an instance of a function template a friend (the second solution presented by #songyuanyao). The difference is that with a Friend Template, all instances of the template function are friends of the class Matrix<>. In this case, I don't think there is any practical difference, but in others, there may be. Therefore, I figured I'd present it anyway.
I think about it like this. Both operators are non-member functions which means they are independent from the class Matrix<>, so think of their prototypes independently:
template<class T>
std::ostream& operator<<(std::ostream& output, const Matrix<T>& matrix);
template<class T>
Matrix<T>* operator*(const Matrix<T>& m1, const Matrix<T>& m2);
Now, replace T with U because to make all instances of them friends of Matrix<>, their prototype needs to be included in the class definition for Matrix<> which is also a template, and it is already using T as its template parameter.
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2);
Now, you can make them friends of Matrix<>. All you need is the appropriate syntax:
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
Finally, they all need to be within the matrixClass namespace, and their declarations and definitions need to be in the right order so that everyone know the others exists:
namespace matrixClass {
// BEGIN Forward declarations
template<class T>
class Matrix;
template<class U>
std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
// END Forward declarations
template<class T>
class Matrix
{
...
template<class U>
friend std::ostream &operator<<(std::ostream&, const Matrix<U> &matrix);
template<class U>
friend Matrix<U>* operator*(const Matrix<U> &m1, const Matrix<U> &m2);
};
...
template<class U>
std::ostream& operator<<(std::ostream& output, const Matrix<U>& matrix)
{
... // your implementation goes here
}
template<class U>
Matrix<U>* operator*(const Matrix<U>& m1, const Matrix<U>& m2)
{
... // your implementation goes here
}
} // end of namespace matrixClass
All this template code should be in the header file, Matrix.h, as it has already been mentioned.
Also, I think that you should change the prototype of operator*() to return Matrix<U> instead of Matrix<U>*. It will behave more like the normal operator*(), and it'll enable you to do things like: Matrix<int> m = m1*m2; or m = m1*m2*m3;. Additionally, the users of your class won't have to worry about deleting the memory allocated by operator*() or the performance cost of the dynamic allocation. Just create a local Matrix<U> variable in operator*() and return it by value; let Return Value Optimization (RVO) take care of the rest.
I'm trying to make << output an entire matrix which I wrote a template for. Not sure why this isn't working, the error is:
error: no match for 'operator[]' (operand types are 'matrix<int' and 'int')
candidate is:
matrix<Comparable> matrix<Comparable>::operator[](matrix<Comparable>&) [with Comparable = int]|
no known conversion for argument 1 from 'int' to 'matrix<int>&'|
which refers to this line: o << rhs[ i ][ j ]. Am I supposed to overload [ ] as well?
matrix.h:
template <typename Comparable>
class matrix
{
private:
size_t num_cols_;
size_t num_rows_;
Comparable **array_;
public:
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
size_t NumRows();
size_t NumCols();
};
matrix.cpp:
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){
size_t c = rhs.NumRows();
size_t d = rhs.NumCols();
for (int i = 0; i < c; i++){
for (int j = 0; j < d; j++){
o << rhs[i][j]; //error
}
}
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows(){
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols(){
return num_cols_;
}
And probably irrelevant but I implemented the matrix like this:
array_ = new Comparable*[num_rows_];
for (int i = 0; i < num_rows_; i++){
array_[i] = new Comparable[num_cols_];
Your function signatures don't match:
ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
is not
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs);
Notice that one is not a template, and the other is. Also, the first has a const reference argument for rhs and the second has just a reference. This mismatch means the function you define isn't Matrix's friend, and so can't access the private (or protected members of Matrix)
What you want is to declare a templated function, and then inform the compiler that a single instantiation (say ostream& operator<<(ostream& out, const matrix<int>& val) ) is the single function you want to be friends with matrix<int>.
To do this, you need to declare that you want only a specific version of the function template, and to do that you need to declare the template, and to do that you need to declare the templated class.
Ultimately that whole chain of declarations might look something like this:
#include <iostream>
// forward declare the class so the compiler knows what's up at the
// templated operator<< declaration.
template <typename T>
class Foo;
// forward declare the templated operator<< so the compiler knows you're
// 'friend'ing a specific instantiation of this template in the
// class definition.
template <typename T>
std::ostream& operator<<(std::ostream& out, const Foo<T>& value);
template <typename T>
class Foo{
// declare the instantiation of the operator<< template that shares
// T with the class template to be a friend:
// operator<<<> can be separated out into operator<< <>
friend std::ostream& operator<<<>(std::ostream& out, const Foo<T>& value);
int bar_;
public:
Foo(int bar) : bar_{bar}{}
};
// now that you know the contents of `Foo<T>`, define the templated operator<<
template <typename T>
std::ostream& operator<<(std::ostream& out, const Foo<T>& value){
return std::cout << "Foo: " << value.bar_;
}
int main(){
Foo<int>
a{2},
b{3};
std::cout << a << '\n' << b;
}
Live on Coliru
You can read further on Template Friends on the C++ Super-FAQ.
You can declare a get function to access array_ instead of making it as an public member;
I thought friend functions had access to all members. Even in this question it worked:
C++ friend function can't access private members
The answer given in that question seems identical to my code, and his compiled fine while mine just says array_ is pivate. Anyone know why?
.h:
#ifndef matrix_h
#define matrix_h
#include <iostream>
using namespace std;
template <typename Comparable>
class matrix
{
private:
size_t num_cols_;
size_t num_rows_;
Comparable **array_;
public:
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
size_t NumRows();
size_t NumCols();
};
#endif
.cpp:
#include <iostream>
#include "matrix.h"
using namespace std;
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){
size_t c = rhs.NumRows();
size_t d = rhs.NumCols();
for (int i = 0; i < c; i++){
for (int j = 0; j < d; j++){
o << rhs.array_[i][j]; //not allowed
}
o << endl;
}
return o;
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows(){
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols(){
return num_cols_;
}
int main(){
matrix<int> a;
cout << a << endl;
}
Say you use const in both places and add const to the declarations of numRows and numCols too. Then what's the problem? Well...
You think it's identical, but your code has a template. And the friend declaration
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
is not a template, so it doesn't match the definition
template <typename Comparable>
ostream& operator<< (ostream& o, matrix<Comparable> & rhs){ // ...
which is a template. In fact gcc will give a warning:
matrix.h:16:79: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, const matrix<Comparable>&)’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<< (ostream& o, const matrix<Comparable> & rhs);
^
matrix.h:16:79: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
It's tempting to just friend all specializations, like this:
template <typename T>
friend ostream& operator<< (ostream& o, const matrix<T> & rhs);
Unfortunately, this won't work for the reasons explained here: Why can templates only be implemented in the header file? You'll be able to compile matrix.cpp, but not a separate driver program, like this:
#include <iostream>
#include "matrix.h"
using namespace std;
int main() {
matrix<int> m;
cout << m << endl;
}
You get an undefined reference error. Instead, you really should just define your entire matrix class in the header and ditch the .cpp file.
It should be pointed out that this still has a problem: you can call this operator<< just fine, but you can't, say, take its address, because it can only be found by argument-dependent lookup.
auto ptr = static_cast<ostream&(*)(ostream&, const matrix<int>&)>(operator<<); // error
For it to be found by unqualified lookup, it must have a matching declaration at namespace scope. And it is actually impossible to write such a declaration (the syntax of C++ doesn't have any way to do it)! To fix this, we need to turn operator<< into a function template, defined inline:
template <typename Comparable>
class matrix {
// ...
template <typename T>
friend ostream& operator<<(ostream& o, const matrix<T>& rhs) {
// ...
}
// ...
};
// namespace-scope declaration
template <typename T>
ostream& operator<<(ostream& o, const matrix<T>& rhs);
Now the above code taking the address of the operator will work.
The compiler complains because the function you implement is different with the one you declare(in declaration rhs is decorated by const, in implementation it isn't).
After you add const in implementation, the compiler complains "Undefined reference" because the declaration and the implementation is still not the same. The implementation is a template function, the decalartion is not.
#ifndef matrix_h
#define matrix_h
#include <iostream>
using namespace std;
template <typename Comparable>
class matrix
{
private:
size_t num_cols_;
size_t num_rows_;
Comparable **array_;
public:
template<typename T>
friend ostream& operator<< (ostream& o, const matrix<T> & rhs);
size_t NumRows() const;
size_t NumCols() const;
};
template <typename Comparable>
ostream& operator<< (ostream& o, const matrix<Comparable> & rhs){
size_t c = rhs.NumRows();
size_t d = rhs.NumCols();
for (int i = 0; i < c; i++){
for (int j = 0; j < d; j++){
o << rhs.array_[i][j]; //not allowed
}
o << endl;
}
return o;
}
template <typename Comparable>
size_t matrix<Comparable>::NumRows() const{
return num_rows_;
}
template <typename Comparable>
size_t matrix<Comparable>::NumCols() const{
return num_cols_;
}
#endif
I cant understand a behavior of operator<< in my class:
header:
#ifndef VECTOR_H_
#define VECTOR_H_
#include <string>
#include <iostream>
template<class T>
class Vector {
static const int EXPANDER = 10;
T* array;
int next;
int length;
void expand();
void contract();
public:
Vector();
Vector(const Vector& v);
void add(const T e);
T get(int index) const;
bool removeByIndex(int index);
bool remove(T e);
int size() const;
T operator[](int i) const;
T& operator+=(const T& t);
T operator+(const T& s);
friend std::ostream& operator<< (std::ostream& os, const Vector<T>& obj);
friend std::istream& operator>> (std::istream& is, Vector<T>& obj);
std::string toString();
~Vector();
};
#endif /* VECTOR_H_ */
vector.cpp
#include "Vector.h"
#include <string>
#include <sstream>
template<class T>
Vector<T>::Vector() {
length = EXPANDER;
next = 0;
array = new T[EXPANDER];
}
template<class T>
Vector<T>::Vector(const Vector& v) {
length = v.next + 1 + EXPANDER;
next = v.next;
array = new T[length];
for (int i = 0; i <= v.next; i++) {
array[i] = v.array[i];
}
}
template<class T>
void Vector<T>::add(const T e) {
if (next >= length - 1)
expand();
array[next++] = e;
}
template<class T>
T Vector<T>::get(int index) const {
if (index > next)
return -1;
return array[index - 1];
}
template<class T>
bool Vector<T>::removeByIndex(int index) {
if (index > next)
return false;
for (int i = index; i < length; i++) {
array[i] = array[i + 1];
}
next--;
contract();
return true;
}
template<class T>
bool Vector<T>::remove(T e) {
int index = -1;
for (int i = 0; i < next; i++) {
if (array[i] == e) {
index = i;
break;
}
}
if (index == -1)
return false;
return removeByIndex(index);
}
template<class T>
int Vector<T>::size() const {
return next;
}
template<class T>
void Vector<T>::expand() {
length += EXPANDER;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
void Vector<T>::contract() {
if (next + EXPANDER >= length)
return; // NO need to contract
length = next + EXPANDER + 1;
T* temp = new T[length];
for (int i = 0; i < next; i++) {
temp[i] = array[i];
}
delete[] array;
array = temp;
}
template<class T>
T Vector<T>::operator[](int i) const {
return get(i);
}
template<class T>
T& Vector<T>::operator+=(const T& t) {
for (int i = 0; i < t.size(); i++) {
add(t.get(i));
}
return *this;
}
template<class T>
T Vector<T>::operator+(const T& s) {
this += s;
return this;
}
template<class T>
std::ostream& operator<< (std::ostream& os, Vector<T>& obj) {
os << obj.toString();
return os;
}
template<class T>
std::istream& operator>> (std::istream& is, Vector<T>& obj) {
int size;
T temp;
is >> size;
for (int i = 0; i < size; i++) {
is >> temp;
add(temp);
}
return is;
}
template<class T>
std::string Vector<T>::toString() {
using namespace std;
ostringstream sb;
sb << "Elements(" << size() << "): [";
for (int i = 0; i < next; i++) {
sb << array[i] << ", ";
}
string r;
r = sb.str();
r = r.substr(0, r.size() - 2) + string("]");
return r;
}
template<class T>
Vector<T>::~Vector() {}
and i run this code with main.cpp
#include "Vector.h"
#include "Vector.cpp"
#include <string>
#include <iostream>
using namespace std;
int main() {
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl;
}
the magic is in operator<< declaration in header. if i delete CONST modifier, compiler says: Undefined reference to operator<<, but with const it works. It is interesting that in my implementation, in cpp, I doesn't have CONST.
btw, how to solve warnings with warning: friend declaration declares a non-template function for operators?
You should learn how to boil this down to a Short, Self-Contained, Compilable Example aka Minimal Working Example.
Here's an SSCCE that demonstrates the problem:
#include <iostream>
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
T get() const { return m; }
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T>& v)
{
// accessing a private member leads to a compiler error here:
return o << "[function template]" << /*v.m*/ v.get();
}
// remove this function to get the same behaviour as in the OP
std::ostream& operator<<(std::ostream& o, Vector<int> const& v)
{
return o << "function" << v.m;
}
int main()
{
Vector<int> v(42);
std::cout << v;
}
Note that it's only about 30 lines long and fits onto one screen w/o scroll bars.
Now, the problem is based upon the friend declaration inside your class template:
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
This looks up a function named operator<< in the surrounding scopes, to befriend this already existing function. But it doesn't find any that matches those parameter type. Therefore, it declares a new function in the surrounding (= global) namespace. This function looks like this:
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
(in the global namespace)
Note: it can only be found via Argument-Dependent Lookup if it's only declared via a friend-declaration.
Now, you later declare a function template of the same name. But the compiler cannot know that you meant to befriend this function template when you wrote the friend declaration inside you class template before. So those two, the friend function and the function template, are unrelated.
What happens now is the usual overload resolution. The function template is preferred if you don't add a const, since you call it with a non-const argument:
Vector<int> v;
v.add(1);
v.add(2);
cout << v << endl; // v is not const
for this argument of type Vector<int>, the binding to Vector<int>& of the function template (specialization) is preferred over the binding to the Vector<int> const& of the friend function. Hence, the function template is chosen, which has a definition (function body) and everything compiles, links and works. Note that the function template is not befriended, but this doesn't raise an error since you don't use any private members.
Once you add the const to the function template, the function template is no longer a better match for the argument. As we have a function and a function template with the same overload "rank", the non-template is preferred. Ergo, the friend function is called, which has no definition => a linker error occurs.
The simplest solution is to define the friend function inside the class definition:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
};
A solution using forward-declarations:
template<class T>
class Vector;
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v);
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
friend std::ostream& operator<< <T>(std::ostream& o, Vector<T> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
Now, the compiler can find the forward-declared function template and befriend this existing function (the specialization of the function template) instead of declaring a new function.
A solution befriending the whole function template:
template<class T>
class Vector
{
private:
T m;
public:
Vector(T p) : m(p) {}
template<class U>
friend std::ostream& operator<<(std::ostream& o, Vector<U> const& v);
};
template<class T>
std::ostream& operator<<(std::ostream& o, Vector<T> const& v)
{
return o << v.m;
}
In this solution, the friend-declaration declares a function template, and the later declaration at namespace scope following the class' definition redeclares this function template.