Overloading istream>> and ostream<< in a templated class - c++

I want to overload >> and << in a templated class and I'm getting some errors.
Severity Code Description Project File Line Suppression State
Error LNK2019 unresolved external symbol "class std::basic_istream<char,struct std::char_traits<char> > & __cdecl operator>>(class std::basic_istream<char,struct std::char_traits<char> > &,class MatricePatratica<int> &)" (??5#YAAAV?$basic_istream#DU?$char_traits#D#std###std##AAV01#AAV?$MatricePatratica#H###Z) referenced in function _main ConsoleApplication3 C:\Users\Octavian\source\repos\ConsoleApplication3\ConsoleApplication3\Source.obj 1
Error LNK2019 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 MatricePatratica<int> const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$MatricePatratica#H###Z) referenced in function _main ConsoleApplication3 C:\Users\Octavian\source\repos\ConsoleApplication3\ConsoleApplication3\Source.obj 1
Error LNK1120 2 unresolved externals ConsoleApplication3 C:\Users\Octavian\source\repos\ConsoleApplication3\Debug\ConsoleApplication3.exe 1
AFAIK this happens when a function is declared but not implemented. I get those errors for overloading >> << (as you can see above)
The only thing is that I implemented those functions so I expected it to work. But I might be missing something.
Here's my templated class
#pragma once
template <typename T>
class MatricePatratica
{
private:
T** date;
int n = 0;
public:
MatricePatratica();
MatricePatratica(int);
MatricePatratica(const MatricePatratica&);
friend std::istream& operator>>(std::istream& is, MatricePatratica<T>& obj);
friend std::ostream& operator<<(std::ostream& os, const MatricePatratica<T>& obj);
};
template<typename T>
inline MatricePatratica<T>::MatricePatratica()
{
}
template<typename T>
inline MatricePatratica<T>::MatricePatratica(int n) :n(n)
{
date = new int* [n];
for (int i = 0; i < n; i++)
{
date[i] = new int[n];
}
}
template<typename T>
inline MatricePatratica<T>::MatricePatratica(const MatricePatratica& deCopiat)
{
date = new int* [deCopiat->n];
for (int i = 0; i < deCopiat->n; i++)
{
date[i] = new int[deCopiat->n];
}
for (int i = 0; i < deCopiat->n; i++)
{
for (int j = 0; j < deCopiat->n; j++)
{
date[i][j] = deCopiat[i][j];
}
}
}
template <typename T>
std::istream& operator>>(std::istream& is, MatricePatratica<T>& obj)
{
for (int i = 0; i < obj.n; i++)
{
for (int j = 0; j < obj.n; j++)
{
is >> obj.date[i][j];
}
}
return is;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const MatricePatratica<T>& obj)
{
for (int i = 0; i < obj.n; i++)
{
for (int j = 0; j < obj.n; j++)
{
os << obj[i][j] << " ";
}
os << std::endl;
}
return os;
}
and here's the main file:
#include <iostream>
#include "MatricePatratica.h"
int main()
{
MatricePatratica<int> test(5);
std::cin >> test;
std::cout << test;
}
Why am I getting this error and how should I fix it?
Live demo

Problem is that you have declared a friendship to something what is not a template!
So compiler tries to find:
std::istream& operator>>(std::istream& is, MatricePatratica<int>& obj)
Which doesn't exists, when in fact it should use:
// note extra template parameter:
std::istream& operator>><int>(std::istream& is, MatricePatratica<int>& obj)
To fix it you need declare friendship to a template of those operators:
template <typename T>
class MatricePatratica
{
....
template<typename U>
friend std::istream& operator>>(std::istream& is, MatricePatratica<U>& obj);
template<typename U>
friend std::ostream& operator<<(std::ostream& os, const MatricePatratica<U>& obj);
};
After fixing typo it works: https://wandbox.org/permlink/gHEmap8zCCTyBjRA

Here's an alternate method of getting the friend functions to work. There's a bit more code, but it has the perk of tying the friend function instantiations to those of the class.
The issue with the accepted answer is that it is too free. Say you have a MatricePatratica<int>. It has as friends all possible versions of your operator<<() and operator>>(); as in operator<< <double>() is a friend of your MatricePatratica<int> and the version for <std::string> and so on. It becomes possible to attempt to use a friend function that isn't compatible with the class type.
The version of your header below fixes that.
My reference is this link, and it contains a concrete example of how the accepted answer can bite you.
#pragma once
#include <iostream> // CHANGE: Include what you use
// CHANGE: Forward declare class and friends
template <typename T>
class MatricePatratica;
template <typename T>
std::istream& operator>>(std::istream& is, MatricePatratica<T>& obj);
template <typename T>
std::ostream& operator<<(std::ostream& os, const MatricePatratica<T>& obj);
template <typename T>
class MatricePatratica
{
private:
T** date;
int n = 0;
public:
MatricePatratica();
MatricePatratica(int);
MatricePatratica(const MatricePatratica&);
// Note movement of <T>
friend std::istream& operator>><T>(std::istream& is, MatricePatratica& obj);
friend std::ostream& operator<<<T>(std::ostream& os, const MatricePatratica& obj);
};
template<typename T>
inline MatricePatratica<T>::MatricePatratica()
{
}
template<typename T>
inline MatricePatratica<T>::MatricePatratica(int n) :n(n)
{
date = new int* [n];
for (int i = 0; i < n; i++)
{
date[i] = new int[n];
}
}
template<typename T>
inline MatricePatratica<T>::MatricePatratica(const MatricePatratica& deCopiat)
{
date = new int* [deCopiat->n];
for (int i = 0; i < deCopiat->n; i++)
{
date[i] = new int[deCopiat->n];
}
for (int i = 0; i < deCopiat->n; i++)
{
for (int j = 0; j < deCopiat->n; j++)
{
date[i][j] = deCopiat[i][j];
}
}
}
template <typename T>
std::istream& operator>>(std::istream& is, MatricePatratica<T>& obj)
{
for (int i = 0; i < obj.n; i++)
{
for (int j = 0; j < obj.n; j++)
{
is >> obj.date[i][j];
}
}
return is;
}
template <typename T>
std::ostream& operator<<(std::ostream& os, const MatricePatratica<T>& obj)
{
for (int i = 0; i < obj.n; i++)
{
for (int j = 0; j < obj.n; j++)
{
os << "TEST" /*obj[i][j]*/ << " "; // CHANGE: Due to compilation error
}
os << '\n'; // CHANGE: Best to avoid baking in obvious inefficiences
}
return os;
}
Now, per my reference, this approach is also not without its downside. There are cases where the template may not make an expected implicit conversion.
The surest way to get a friend function to behave completely as expected in a template class is to implement it inline (I mean in the class declaration). I don't believe your class will hit that edge case, and the method above is usually what I do.

Related

Overloading operator<< template classes [duplicate]

This question already has answers here:
C++ template/ostream operator question
(2 answers)
What is the right way to write friend function declarations in template class?
(1 answer)
overloading friend operator<< for template class
(5 answers)
Closed 1 year ago.
I am using Microsoft Visual Studio for source code editor, and when I try to compile the below code I got an linker error:
LNK2019 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 X<int> &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#AAV?$X#H###Z) referenced in function _main Zadatak7.19.04.2021 C:\Users\AT95\Desktop\Zadatak7.19.04.2021\Zadatak7.19.04.2021\main.obj 1
What must I do to make this program work correctly?
I want you to look at the definition of the overloading operator<< because
that method is causing errors.
#include <iostream>
template <class T>
class X
{
private:
int index, capacity;
T* collection{};
public:
X(const int nmb, const T* array)
{
index = 0;
capacity = nmb;
collection = new(T[nmb]);
for (int i = 0; i < nmb; i++)
collection[index++] = array[i];
}
X(const X& other)
{
index = other.index;
capacity = other.capacity;
collection = new(T[other.capacity]);
if(other.index < other.capacity)
for (int i = 0; i < other.index; i++)
collection[i] = other.collection[i];
}
~X() { delete[] collection; }
friend std::ostream& operator<<(std::ostream&, X<T>&);
};
template <class T>
std::ostream& operator<<(std::ostream& out, X<T>& other)
{
for (int i = 0; i < other.index; i++)
out << i + 1 << ". " << other.collection[i];
return out;
}
int main()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, n = sizeof(array)/sizeof(int);
X<int> x(n, array), b(x);
std::cout << x;
return 0;
}
Your friend dclaration is wrong.
friend std::ostream& operator<<(std::ostream&, X<T>&);
This is a friend declaration of a non templated operator<<.
It should look like this:
template<typename Z>
friend std::ostream& operator<<(std::ostream&, X<Z>&);
But there is a better way to declare it. Move the function body into the class then you don't need to declare the template part.
template <class T>
class X
{
// STUFF AS BEFORE
// Friend class definition.
friend std::ostream& operator<<(std::ostream& out, X& other)
{
for (int i = 0; i < other.index; i++)
out << i + 1 << ". " << other.collection[i];
return out;
}
}
Secondary note. In output operators the object being output is usually declared const (as outputting it should not modify it).
friend std::ostream& operator<<(std::ostream& out, X const& other)
^^^^^
You need to write the template keyword at the beginning of the friend function, like this:
#include <iostream>
template <class T>
class X
{
private:
int index, capacity;
T* collection{};
public:
X(const int nmb, const T* array)
{
index = 0;
capacity = nmb;
collection = new(T[nmb]);
for (int i = 0; i < nmb; i++)
collection[index++] = array[i];
}
X(const X& other)
{
index = other.index;
capacity = other.capacity;
collection = new(T[other.capacity]);
if(other.index < other.capacity)
for (int i = 0; i < other.index; i++)
collection[i] = other.collection[i];
}
~X() { delete[] collection; }
template<class U> friend std::ostream& operator<<(std::ostream&, X<U>&);
};
template <class T>
std::ostream& operator<<(std::ostream& out, X<T>& other)
{
for (int i = 0; i < other.index; i++)
out << i + 1 << ". " << other.collection[i];
return out;
}
int main()
{
int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }, n = sizeof(array)/sizeof(int);
X<int> x(n, array), b(x);
std::cout << x;
return 0;
}

error LNK2019: unresolved external symbol

i have a template class, and when im runing the program it says
error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class CSet &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#AAV?$CSet#H###Z) referenced in function "public: void __thiscall Menu::menu(void)" (?menu#Menu##QAEXXZ)
on any kind of data structure i try to use,
if anyone can explain to me why the overloading of printing function makes this error i'll be happy to ear about it.
template <class T> class CSet{
T* Array;
int size;
public:
CSet()
{
Array = NULL;
size = 0;
}
CSet(CSet& other){
size = other.size;
Array = new T[size];
for (int i = 0; i < size; i++)
Array[i] = other.Array[i];
}
friend ostream& operator <<(ostream& out, CSet& other);
~CSet()
{
if (size > 0)
delete[] Array;
}
};
template <class T> ostream& operator <<(ostream& out, CSet<T>& other){
out << "(";
for (int i = 0; i < other.size; i++){
if (size>1)
out << other.Array[i] < ",";
else
out << other.Array[i];
}
out << ")" << endl;
return out;
}
The friend declaration does not declare a function template, but a separate function for each instantiation of the class template. Therefore, the template you define is not the same as these functions, which remain undefined.
There are two options to fix this.
Either define the friend operator inside the class, rather than just declaring it there:
friend ostream& operator <<(ostream& out, CSet& other) {
// implementation
}
Or declare the function template before the class definition:
template <class T> class CSet;
template <class T> ostream& operator <<(ostream& out, CSet<T>&);
and declare the template to be a friend:
friend ostream& operator << <T>(ostream& out, CSet&);
^^^

When using templates, how do I fix the following compiler error to achieve the desired behavior of my program?

I'm practicing templates in Visual Studio 2013 from a not so well written C++ book and I receive the following compiler errors respectively, "error C4430: missing type specifier - int assumed. Note: C++ does not support default-int" and "error C2143: syntax error : missing ',' before '<'".
Both refer me to line 10 which is...
std::ostream& operator<< (std::ostream&, const Array<T>&);
The desired behavior of my code is to show the creation and destruction of temporary Animal objects using templates.
The troubleshooting steps I have tried so far include substituting std::iostream& with int in my return type and first parameter type of line 10. After doing so the error messages remained the same. This seemed to suggest that the problem may be the second parameter type. I then added the keyword typename to the second parameter of my overloading operator function (operator<<) on line 10 and the error still persisted.
Line 10 can be found in the header file below.
//Array.h
#ifndef ARRAY_H
#define ARRAY_H
#include <iostream>
#include "Animal.h"
const int DefaultSize = 3;
template <typename T>
std::ostream& operator<< (std::ostream&, const Array<T>&);
template <typename T> // declare the template and the paramenter
class Array // the class being parameterized
{
public:
Array(int itsSize = DefaultSize);
Array(const Array &rhs);
~Array() { delete[] pType; }
// operators
Array& operator=(const Array&);
T& operator[](int offSet) { return pType[offSet]; }
const T& operator[](int offSet) const { return pType[offSet]; }
// accessors
int GetSize() const { return itsSize; }
// friend function
friend std::ostream& operator<< (std::ostream&, const Array<T>&);
private:
T *pType;
int itsSize;
};
template <typename T>
Array<T>::Array(int size = DefaultSize) :itsSize(size)
{
pType = new T[size];
for (int i = 0; i < size; i++)
pType[i] = static_cast<T>(0);
}
Array<Animal>::Array(int AnimalArraySize) :itsSize(AnimalArraySize)
{
pType = new Animal[AnimalArraySize];
}
template <typename T>
Array<T>::Array(const Array &rhs)
{
itsSize = rhs.GetSzie();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
}
template <typename T>
Array<T>& Array<T>::operator=(const Array &rhs)
{
if (this == &rhs)
return *this;
delete[] pType;
itsSize = rhs.GetSize();
pType = new T[itsSize];
for (int i = 0; i < itsSize; i++)
pType[i] = rhs[i];
return *this;
}
template <typename T>
std::ostream& operator<< (std::ostream& output, const Array<T> &theArray)
{
for (int i = 0; i < theArray.GetSize(); i++)
output << "[" << i << "]" << theArray[i] << std::endl;
return output;
}
#endif
Here's the rest of my code from my book for your reference.
//Animal.h
#ifndef ANIMAL_H
#define ANIMAL_H
#include <iostream>
class Animal
{
public:
// constructors
Animal();
Animal(int);
~Animal();
// accessors
int GetWeight() const { return itsWeight; }
void SetWeight(int theWeight) { itsWeight = theWeight; }
// friend operators
friend std::ostream& operator<<(std::ostream&, const Animal&);
private:
int itsWeight;
};
#endif
//Animal.cpp
#include "Animal.h"
#include <iostream>
Animal::Animal() :itsWeight(0)
{
std::cout << "animal() ";
}
Animal::Animal(int weight) : itsWeight(weight)
{
std::cout << "animal(int) ";
}
Animal::~Animal()
{
std::cout << "Destroyed an animal...";
}
//Main.cpp
#include <iostream>
#include "Animal.h"
#include "Array.h"
std::ostream& operator<<(std::ostream&, const Animal&);
void IntFillFunction(Array<int>& theArray);
void AnimalFillFunction(Array<Animal>& theArray);
int main()
{
Array<int> intArray;
Array<Animal> animalArray;
IntFillFunction(intArray);
AnimalFillFunction(animalArray);
std::cout << "intArray...\n" << intArray;
std::cout << "\nanimalArray...\n" << animalArray << std::endl;
std::cin.get();
return 0;
}
std::ostream& operator<<(std::ostream& theStream, const Animal& theAnimal)
{
theStream << theAnimal.GetWeight();
return theStream;
}
void IntFillFunction(Array<int>& theArray)
{
bool Stop = false;
int offset, value;
while (!Stop)
{
std::cout << "Enter an offset (0-9) and a value. ";
std::cout << "(-1 to stop): ";
std::cin >> offset >> value;
if (offset < 0)
break;
if (offset > 9)
{
std::cout << "***Please use values between 0 and 9.***\n";
continue;
}
theArray[offset] = value;
}
}
void AnimalFillFunction(Array<Animal>& theArray)
{
Animal *pAnimal;
for (int i = 0; i < theArray.GetSize(); i++)
{
pAnimal = new Animal(i * 10);
theArray[i] = *pAnimal;
delete pAnimal;
}
}
I've tried my best to keep this question on topic by providing you with the desired behavior of the program, a specific problem or error and the shortest code necessary to reproduce it. All of which are requirements for debugging help as documented in the Help Center page.
I'm new to this website, and if my question is still off-topic, please let me know how I can change my question to be more on topic or inform me of a better place to ask my question. - Thank you
This function is declared before the Array class is declared (i.e., the compiler has never seen that type and doesn't know what it is, hence your error).
template<typename> class Array; // Add this forward declaration
template <typename T>
std::ostream& operator<< (std::ostream&, const Array<T>&);
Edit
I just noticed that the operator<< is declared before the Array class and as a friend function within the Array class. You could just remove the declaration at the top.
Edit 2
Array.h
I removed the following items
#include "Animal.h"
template <typename T>
std::ostream& operator<< (std::ostream&, const Array<T>&);
Array<Animal>::Array(int AnimalArraySize) :itsSize(AnimalArraySize)
{
pType = new Animal[AnimalArraySize];
}
Updated the friend function declartion to be
template<typename T> // This is not a member function so must be declared as a template
friend std::ostream& operator<< (std::ostream&, const Array<T>&);
Animal.h
This class has the friend function but it's not implemented in the cpp file. I moved the definition from the main.cpp into Animal.cpp

How to overload the << operator?

I am trying to build my own std::vector class but I am having trouble overloading the subscript ([]) and the cout << operators.
So far, I have tried to define the << operator as a public member of the class and then write the function's body outside the class declaration.
Right now I am getting terminal pages full of errors from iostream library and I do not even know where to begin looking through them.
I am a beginner in C++ and not accustomed to friend keyword or the template keyword. What am I doing wrong?
template<typename T>
class MyVector {
private:
T* Array;
public:
T& operator[](int b)
{
...
}
std::ostream& output(std::ostream& s) const;
};
std::ostream& operator<<(std::ostream& output, MyVector& A)
{
int i;
for(i = 0; i < A.GetDimension(); i++)
{
output << A[i] << " ";
}
output << "\n";
return output;
};
What you have is right, you just forgot the template declaration:
template <typename T>
std::ostream& operator<<(std::ostream& output, MyVector<T>& A)
{
int i;
for (i = 0; i < A.GetDimension(); i++)
{
output << A[i] << " ";
}
output << "\n";
return output;
};
template<typename T>
class MyVector{
...
std::ostream& printToStream(std::ostream& output) const {
int i;
for (i = 0; i < Dimension; i++) {
output << Array[i] << " ";
}
output << "\n";
return output;
}
...
};
template<typename T>
std::ostream& operator<<(std::ostream& output, const MyVector<T>& A) {
return A.printToStream(output);
}

Left of '.size' must have class/struct/union

Still cannot get this one to work. Please help!
template <typename T>
class Container{
public:
...
friend ostream& operator<<(ostream& ostr, const Container<T>& C)
{
for(size_t i=0; i!= data.size(); i++) // ERROR
ostr<<data[i]<<" ";
return ostr;
}
private:
vector<T> data;
};
data is a member of C and should therefore be accessed as C.data (remember that your operator<< is a free function and not a member of Container):
for(size_t i = 0; i != C.data.size(); ++i)
ostr << C.data[i] << " ";