This question already has answers here:
C++ templates and friends, linker error
(1 answer)
Friend template overloaded operator <<: unresolved external symbol
(3 answers)
Linker error when operator== is a friend [duplicate]
(1 answer)
overloading friend operator<< for template class
(5 answers)
Closed 4 years ago.
I've encountered the following exercises while studying templates:
#include <iostream>
using namespace std;
template <class T>
class A {
T _v;
public:
A() {}
A(T v) : _v(v) {}
friend ostream & operator<<(ostream & c, const A<T> & v);
};
template <class T>
ostream & operator<<(ostream & c, const A<T> & v){
c << v._v; return c;
}
int main()
{
A<int>a(10);
cout << a << endl;
return 0;
}
This code snippet should produce an error during compilation and it actually does. It's a linker error, but I can't understand it.
I tried to change a few lines of code and the error seems to be caused by the instation of the template operator<<, since removing that template and writing a specific operator make the code work. I also have the feeling that the template gets instantiated multiple times, not only for int.
However, to my limited knowledge, the template definition seems fine. What am I missing?
The exact error (VS 2017) is:
Error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class A const &)" (??6#YAAEAV?$basic_ostream#DU?$char_traits#D#std###std##AEAV01#AEBV?$A#H###Z) referenced in function main
You need to declare the friend function as template:
class A {
...
template <class U> // <-- NOTICE ---------------v
friend ostream & operator<<(ostream & c, const A<U> & v);
...
Or better yet, use a safer approach, despite a bit more verbose:
#include <iostream>
using namespace std;
template <class T>
class A;
template <class T>
ostream& operator<<(ostream& c, const A<T>& v);
template <class T>
class A {
T _v;
public:
A() {}
A(T v) : _v(v) {}
friend ostream& operator<< <T>(ostream& c, const A<T>& v);
};
template <class T>
ostream& operator<<(ostream& c, const A<T>& v) {
c << v._v;
return c;
}
int main() {
A<int> a(10);
cout << a << endl;
return 0;
}
See this page for more details.
Related
When separating the declaration/definition of (a friend function + a class template) an error occurs:
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 Property<int> const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$Property#H###Z)
Note that when using a friend function without a class template or vice versa everything works fine
but when using the two things together an error occurs.
I tried to instantiate the template in the .cpp file but it didn't succeed.
Also, I have included the .cpp file at end of the .h file but it didn't work either.
class.h
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
friend std::ostream& operator<<(std::ostream& os, Property<PropertyType>& other);
};
class.cpp
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}
template <class PropertyType>
std::ostream& operator<<(std::ostream& os, Property<PropertyType>& other) {
os << other.m_property;
return os;
}
template Property<int>;
main.cpp
int main() {
Property<int> num;
num = 100;
std::cout << num << "\n";
}
What is wrong with them when separating the declaration/definition into two files and they are used together?
There are two problems with your code snippet.
The first problem is that you've put the implementation in the source file instead of the header file. So to solve this just move the implementation into the header file.
The second problem is that even if you move the implementation into the source file the program will still not work(Demo). This is because the friend declaration that you currently have(for overloaded opearator<<), is for an ordinary(non-template) function. That is, in your original code operator<< for class template Property<> is not function template, but “ordinary” function instantiated with the class template if needed. It is what we call a templated entity.
But the definition that you've provided in the source file(.cpp) for the overloaded operator<< is for a function template and not for an oridnary function. Thus, for the statement std::cout << num << "\n"; the linker cannot find the definition/implementation corresponding to the ordinary overloaded operator<< for which you had the friend declaration.
There are two ways to solve this:
Method 1
Add a separate parameter clause in the friend declaration.
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
template<typename T> //parameter cluase added here
//---------------------------------------------------vvvvv----------------------->const added here
friend std::ostream& operator<<(std::ostream& os,const Property<T>& other);
};
template <class PropertyType>
//----------------------------------------vvvvv---------------------------------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
Demo
Method 2
Here we provide forward declaration for the overloaded operator<<.
//forward declaration for class template Property
template<typename T> class Property;
//forward declaration for overloaded operator<<
template<typename T> std::ostream& operator<<(std::ostream&,const Property<T>&);//note the const in the second parameter
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
//---------------------------------vvvvvvvvvvvvvv---------------------------------> angle brackets used here
friend std::ostream& operator<<<PropertyType>(std::ostream& os,const Property<PropertyType>& other);//also note the const in the second parameter
};
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}
template <class PropertyType>
//----------------------------------------vvvvv---------------------------------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
Demo
Method 3
If you want to provide the implementation inside the source file instead of the header file, then you should add
template std::ostream& operator<<(std::ostream& os, Property<int>& other);
inside the source file in addition to adding a template parameter clause for the friend declaration as shown below:
class.h
#ifndef MYCLASS_H
#define MYCLASS_H
#include <iostream>
template <class PropertyType>
class Property {
PropertyType m_property;
public:
const PropertyType& operator=(const PropertyType& value);
template<typename T> //parameter clause added
//---------------------------------------------------vvvvv--------------------->const added here
friend std::ostream& operator<<(std::ostream& os,const Property<T>& other);
};
#endif
class.cpp
#include "class.h"
template <class PropertyType>
const PropertyType& Property<PropertyType>::operator=(const PropertyType& value) {
m_property = value;
return m_property;
}
template<typename PropertyType>
//----------------------------------------vvvvv------->const added here
std::ostream& operator<<(std::ostream& os,const Property<PropertyType>& other) {
os << other.m_property;
return os;
}
template class Property<int>;
template std::ostream& operator<<(std::ostream& os,const Property<int>& other);
main.cpp
#include <iostream>
#include "class.h"
int main() {
Property<int> num;
num = 100;
std::cout << num << "\n";
}
Demo
The changes that I made include:
Added a separate template parameter clause for the friend declaration. This is so that the friend declaration is for a function template. Moreover, we specify a different type parameter named T and not PropertyType because otherwise the new PropertyTypewill shadow the outerPropertyType`.
Added a low-level const to the second parameter of the overloaded opeartor<<.
In method3, inside source file(class.cpp), added
template std::ostream& operator<<(std::ostream& os,const Property<int>& other);
for the non-member function overloaded operator<<.
I'm trying to write the function definition for overloading the operators ">>" and "<<" outside of the class definition, though in the same file, as you can see. I get the following errors:
1>Source.obj : 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 MyClass<int> &)" (??5#YAAAV?$basic_istream#DU?$char_traits#D#std###std##AAV01#AAV?$MyClass#H###Z) referenced in function _main
1>Source.obj : 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 MyClass<int>)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#V?$MyClass#H###Z) referenced in function _main
1>Source.obj : 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 MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > > &)" (??5#YAAAV?$basic_istream#DU?$char_traits#D#std###std##AAV01#AAV?$MyClass#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std#####Z) referenced in function _main
1>Source.obj : 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 MyClass<class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> > >)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#V?$MyClass#V?$basic_string#DU?$char_traits#D#std##V?$allocator#D#2##std#####Z) referenced in function _main
I've been up and down the river with this one. The strange thing is that if I write their definitions inside the class definition, it works flawlessly.
#include <iostream>
#include <string>
using namespace std;
template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {};
friend istream& operator>>(istream&, MyClass<MYTYPE>&);
friend ostream& operator<<(ostream&, MyClass<MYTYPE>);
};
template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
dim = x;
name = y;
myVector = new MYTYPE[dim];
}
template <class MYTYPE>
istream& operator>>(istream& X, MyClass<MYTYPE>& a){
cout<<"Reading vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++){
cout<<a.name<<'['<<indice<<"]= ";
X >> a.myVector[indice];
}
return X;
}
template <class MYTYPE>
ostream& operator<<(ostream& X, MyClass<MYTYPE> a){
X<<"Vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++)
X<<a.myVector[indice]<<' ';
X<<endl;
return X;
}
int main() {
MyClass<int> object(4, "Ints vector");
MyClass<string> object2(5, "String vector");
cin >> object;
cin >> object2;
cout << object;
cout << object2;
system("pause");
return 0;
}
In your code, declarations of friend operators within MyClass should look like these:
template<typename T> friend istream& operator>>(istream&, MyClass<T>&);
template<typename T> friend ostream& operator<<(ostream&, MyClass<T>);
That is, they shall have their own template parameters.
A valid definition for MyClass based on the one provided in the question follows:
template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {}
template<typename T>
friend istream& operator>>(istream&, MyClass<T>&);
template<typename T>
friend ostream& operator<<(ostream&, MyClass<T>);
};
Turning up the warning level of the compiler helps. By using -Wall with g++, I get the following warnings before the linker error.
socc.cc:13:58: warning: friend declaration ‘std::istream& operator>>(std::istream&, MyClass<MYTYPE>& )’ declares a non-template function [-Wnon-template-friend]
friend istream& operator>>(istream&, MyClass<MYTYPE>&);
^
socc.cc:13:58: note: (if this is not what you intended, make sure the function template has already been declared and add <> after the function name here)
socc.cc:14:57: warning: friend declaration ‘std::ostream& operator<<(std::ostream&, MyClass<MYTYPE> ’ declares a non-template function [-Wnon-template-friend]
friend ostream& operator<<(ostream&, MyClass<MYTYPE>);
You need to use function templates for the operator>> and operator<< functions. You can declare them before the definition of the class with:
// Forward the class template.
template <class MYTYPE> class MyClass;
// Declare the function templates.
template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);
template <class MYTYPE>
std::ostream& operator<<(st::ostream&, MyClass<MYTYPE>);
Then, you'll have to use the friend declaration with the appropriate template parameter.
// This makes sure that operator>><int> is not a friend of MyClass<double>
// Only operator>><double> is a friend of MyClass<double>
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
Here's an updated version of your code that builds for me. I haven't tried to run it.
#include <iostream>
#include <string>
using namespace std;
template <class MYTYPE> class MyClass;
template <class MYTYPE>
std::istream& operator>>(std::istream&, MyClass<MYTYPE>&);
template <class MYTYPE>
std::ostream& operator<<(std::ostream&, MyClass<MYTYPE>);
template <class MYTYPE>
class MyClass {
MYTYPE *myVector;
int dim;
string name;
public:
MyClass(int, string);
MyClass() {};
friend std::istream& operator>><MYTYPE>(std::istream&, MyClass<MYTYPE>&);
friend std::ostream& operator<<<MYTYPE>(std::ostream&, MyClass<MYTYPE>);
};
template <class MYTYPE>
MyClass<MYTYPE>::MyClass(int x, string y) {
dim = x;
name = y;
myVector = new MYTYPE[dim];
}
template <class MYTYPE>
std::istream& operator>>(std::istream& X, MyClass<MYTYPE>& a){
cout<<"Reading vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++){
cout<<a.name<<'['<<indice<<"]= ";
X >> a.myVector[indice];
}
return X;
}
template <class MYTYPE>
std::ostream& operator<<(std::ostream& X, MyClass<MYTYPE> a){
X<<"Vector: "<<a.name<<endl;
for(int indice = 0; indice < a.dim; indice++)
X<<a.myVector[indice]<<' ';
X<<endl;
return X;
}
int main() {
MyClass<int> object(4, "Ints vector");
MyClass<string> object2(5, "String vector");
cin >> object;
cin >> object2;
cout << object;
cout << object2;
system("pause");
return 0;
}
It is a bit complicated. Actually there are two ways a class template can have a function friend.
For example, take this:
template <typename T>
void fun();
template <typename T>
class A
{
};
Then what do you want?
Or do you want that func<X>() be friend of A<Y> for any other Y?
Do you want that fun<X>() be friend of A<X> but not of A<Y>?
That is, should the function be able to access privater members of any specialization or only to the specialization of the same type.
My guess is that you need option 2.
The trick is that you must make friend of the function specialization so the template function must already exist: you have declare the template function first and then make it friend. Something like:
//first declare both function and class
template <typename T>
class A;
template <typename T>
void fun();
//Then define the class
template <typename T>
class A
{
//A<T> is friend to fun<T>, the specializations must match.
friend void fun<T>();
};
//And define the function
template <typename T>
void fun()
{
}
If what you want is option 1, then there is no need of the advanced declarations. Just:
template <typename T>
class A
{
//A<T> is friend to fun<X>, T and X may be different
template <class X>
friend void fun();
};
That said, your code is a bit tricky to write because of the << and the >>:
template <class MYTYPE>
class MyClass;
template <class MYTYPE>
istream& operator>>(istream& X, MyClass<MYTYPE>& a);
template <class MYTYPE>
ostream& operator<<(ostream&, MyClass<MYTYPE>);
template <class MYTYPE>
class MyClass {
// ....
friend istream& operator>> <MYTYPE>(istream&, MyClass<MYTYPE>&);
friend ostream& operator<< <MYTYPE>(ostream&, MyClass<MYTYPE>);
};
This is my code:
mov.h
#include <iostream>
template< class T>
class Movie {
public:
Movie(T in) {
a = in;
}
friend std::ostream& operator<<(std::ostream& os, const Movie<T>& movie);
private:
T a;
};
template<class T>
std::ostream& operator<<(std::ostream& os, const Movie<T>& movie) {
return os;
}
main.cpp
#include "mov.h"
int main() {
Movie<int> movie1(1);
std::cout << movie1 << std::endl;
return 0;
}
I try to compile this code, and I get the error:
Error 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 Movie<int> const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$Movie#H###Z) referenced in function _main c:\Users\Adi\documents\visual studio 2013\Projects\bdika01\bdika01\main.obj bdika01
Error 2 error LNK1120: 1 unresolved externals c:\users\adi\documents\visual studio 2013\Projects\bdika01\Debug\bdika01.exe 1 1 bdika01
If I try the code inline like this it's okay:
mov.h
#include <iostream>
template<class T>
class Movie {
public:
Movie(T in) {
a = in;
}
friend std::ostream& operator<<(std::ostream& os, const Movie<T>& movie){
return os;
}
private:
T a;
};
What can I do if I want to separate the defination and declaration?
Thanks.
template <typename T> class Movie;
template<class T>
std::ostream& operator<<(std::ostream& os, const Movie<T>& movie);
template< class T>
class Movie {
friend std::ostream& operator<< <T>(std::ostream& os, const Movie<T>& movie);
};
template<class T>
std::ostream& operator<<(std::ostream& os, const Movie<T>& movie){
return os;
}
In your original code, you befriend a non-template function that just happens to take the right instantiation of Movie<> as a parameter. So, every time a Movie<T> is instantiated, a corresponding non-template operator<< is declared (but not defined) in the enclosing namespace scope. friend declarations are strange this way.
In addition, you declare and define a function template named operator<< (which is not a friend of any instantiation of Movie). However, overload resolution prefers non-templates, other things equal.
I have a template class called "KeyedCollection" that contains functions to insert data into a vector, as well as stream out the data. The vector is a private member function. I can't seem to figure out how to use the information from this vector in my overloading ostream friend function. Note: I cannot change the general structure of the class and the function arguments, they have to stay as they are. I list all of the class for reference, but the function in question is the last one.
#include "stdafx.h"
#include <iostream>
#include <vector>
#include "Windows.h"
#include <string>
using namespace std;
template <class K, class T>
class KeyedCollection {
public:
// Create an empty collection
KeyedCollection();
// Return the number of objects in the collection
int size() const;
// Insert object of type T with a key of type K into the
// collection using an “ignore duplicates” policy
void insert(const K&, const T&);
// Output data value of objects in the collection,
// one data value per line
friend ostream& operator<<(ostream&,
const KeyedCollection&);
private:
// Insert required members here
int objSize;
vector<T> objects;
};
template<class K, class T>
KeyedCollection<K,T>::KeyedCollection() {
objSize = 0;
vector<T> objects;
}
template<class K, class T>
int KeyedCollection<K,T>::size() const {
objSize = objects.size();
return objSize;
}
template<class K, class T>
void KeyedCollection<K,T>::insert(const K&,const T& c) {
objects.push_back(c);
}
// !!! function i am trying to define !!!
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {
outstream<<inst<<endl;
return outstream;
}
Also, I'm getting an error that says
"fatal error LNK1120: 1 unresolved externals"
and one that says
"error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class KeyedCollection const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$KeyedCollection#HVCustomer#####Z) referenced in function _main" ...
Just as a side question, any idea what those could be?
cppreference and Johannes Schaub - litb both provide the same method for getting this to work.
You want to make one single instance (called "specialization" in
generic terms) of that template a friend. You do it the following way
[...]
First make a forward declaration before the definition of your class:
template <class K, class T> class KeyedCollection;
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst);
Because the compiler knows from the parameter list that the template
arguments are T and U, you don't have to put those between <...>, so
they can be left empty.
Then make your friend declaration and be sure to add <> after operator<<:
template <class K, class T>
class KeyedCollection {
public:
// snip
friend ostream& operator<< <> (ostream& outstream,const KeyedCollection<K,T>& inst);
// snip
};
Finally you can define it:
template<class K, class T>
ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {
// Just an example
for (const auto& t : inst.objects)
{
std::cout << t << std::endl;
}
return outstream;
}
Live Example
Alternately, do what Yakk suggested.
template <class K, class T>
class KeyedCollection {
public:
// snip
friend ostream& operator<<(ostream& outstream,const KeyedCollection<K,T>& inst) {
for (const auto& t : inst.objects)
{
std::cout << t << std::endl;
}
return outstream;
}
// snip
};
Live Example
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
overloading friend operator<< for template class
I'm trying to overload operator<< for a template class but I'm getting errors...
Final(fixed) code:
template<class T>
class mytype
{
T atr;
public:
mytype();
mytype(T);
mytype(mytype&);
T getAtr() const;
T& operator=(const T&);
template<class U> friend ostream& operator<<(ostream&,const mytype<U>&);
};
template<class T>
mytype<T>::mytype()
{
atr=0;
}
template<class T>
mytype<T>::mytype(T value)
{
atr=value;
}
template<class T>
mytype<T>::mytype(mytype& obj)
{
atr=obj.getAtr();
}
template<class T>
T mytype<T>::getAtr() const
{
return atr;
}
template<class T>
T& mytype<T>::operator=(const T &other)
{
atr=other.getAtr();
return *this;
}
template<class U>
ostream& operator<<(ostream& out,const mytype<U> &obj)
{
out<<obj.getAtr();
return out;
}
(All in the header file)
VS2012 errors:
1)
Error 1 error LNK2019: unresolved external symbol "public: __thiscall mytype::mytype(int)" (??0?$mytype#H##QAE#H#Z) referenced in function _wmain
2)
Error 2 error LNK2019: unresolved external symbol "class std::basic_ostream > & __cdecl operator<<(class std::basic_ostream > &,class mytype const &)" (??6#YAAAV?$basic_ostream#DU?$char_traits#D#std###std##AAV01#ABV?$mytype#H###Z) referenced in function _wmain
3)
Error 3 error LNK1120: 2 unresolved externals
What's wrong with my code?
You told the compiler to expect a free non-template function:
friend ostream& operator<<(ostream&,const mytype<T>&);
...but then you defined a function template instead:
template<class T>
ostream& operator<<(ostream& out,const mytype<T> &obj)
{
out<<obj.getAtr();
return out;
}
Tell the compiler instead to expect a function template:
template<class T> friend ostream& operator<<(ostream&,const mytype<T>&);
It seems implementation/definition of the constructors is missing.
EDIT I see now the question has been updated and the constructors have been defined.
In this case you just need to put your constructor definitions in your header.
Another way to do this that some people do is to define an .inl(inline) file and include that at the bottom of your header.
Well you declare the constructor
mytype(T);
But you never actually get around to defining it.
The compiler won't create a default body for the above constructor as it has no idea how to do it.
You also need to specify template<class T> in the class's declaration of the operator:
template<class T>
class mytype
{
T atr;
public:
...
T getAtr() const;
template<class U>
friend ostream& operator<<(ostream&,const mytype<U>&);
...
};
Alternatively, implement the operator inside the class:
template<class T>
class mytype
{
T atr;
public:
...
T getAtr() const;
friend ostream& operator<<(ostream&,const mytype<T>&)
{
...
}
...
};
As for the first error, it's probably because you are implementing mytype's constructor in a source file. For template classes, you should implement all methods (and constructors, etc) inside the class.