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
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<<.
numcpp.h file
#include "iostream"
namespace numcpp{
template<typename T>
struct Vector
{
std::vector<T> v;
};
template<typename T>
struct Matrix
{
std::vector<T> m;
//template<typename T>
friend std::ostream& operator << (std::ostream& out, const mf& mat);
};
typedef Vector<float> vf;
typedef Matrix<vf> mf;
}
I am trying to overload << operator for cout to be able to print mf. First I tried making the overloading function a friend that directly takes mf as argument. I did this because if I took Matrix as argument, I would need to deal with template and I don't know how to do that.
numcpp.cpp file
#include "numcpp.h"
namespace numcpp{
std::ostream& operator << (std::ostream& out, const mf& mat)
{
//overloaded out here
return out;
}
}
main.cpp
#include "iostream"
#include "numcpp.h"
int main()
{
numcpp::mf inputs;
// inputs is filled with random numbers here
std::cout << inputs;
}
But this gives an error identified mf is undefined in .h file in line friend std::ostream& operator << (std::ostream& out, const mf& mat);
So I ditched this approach and tried removing the friend function declaration from Matrix without changing the .cpp file. But now I get a different error saying no operator << matches these operands.
I think this is because the overload is done in numcpp namespace so it is not visible from main which is outside the namesapce.
What you normally want is to define a template in your header file. The definition needs to be available at the call-site to allow the compiler to make an instatiation of the template.
If possible, the easiest way is to put the definition in the class definition.
template<typename T>
struct Matrix
{
std::vector<T> m;
// using Matrix here is allowed and refers to the current instatiation, equivalent to writing Matrix<T>
friend std::ostream& operator << (std::ostream& out, const Matrix& mat) {
...
return out;
}
};
Try change your numcpp.h to
namespace numcpp{
template<typename T>
struct Vector
{
std::vector<T> v;
};
typedef Vector<float> vf;
template<typename T>
struct Matrix
{
std::vector<T> m;
//template<typename T>
inline friend std::ostream& operator << (std::ostream& out, const Matrix<vf>& mat);
};
inline std::ostream& operator << (std::ostream& out, const Matrix<vf>& mat)
{
//overloaded out here
return out;
}
typedef Matrix<vf> mf;
}
You are getting this error because mf was not declared when you trying to use it.
Also, you can add the body of the function directly in the definition to get rid of the inline.
The typedefs are not available inside the definition of your class Matrix. You can either declare the typedef before the class definition (#Alloces' answer) of just template the overloaded operator:
#include <vector>
#include <sstream>
#include <iostream>
namespace numcpp {
template<typename T>
struct Vector
{
std::vector<T> v;
};
template<typename T>
struct Matrix
{
std::vector<T> m;
template<typename K> // template parameter must not be named T
inline friend std::ostream& operator << (std::ostream& out, const Matrix<K>& mat);
};
template<typename K>
inline std::ostream& operator << (std::ostream& out, const Matrix<K>& mat)
{
return out << "Just a test";
}
typedef Vector<float> vf;
typedef Matrix<vf> mf;
}
int main() {
numcpp::mf inputs;
std::cout << inputs << "\n"; // Just a test
}
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.
I am working on a template Graph data structure, which is an STL vector of GraphNode objects. I defined the GraphNode class nested inside the Graph class and when I invoke the overloaded insertion operator for the GraphNode object inside the overloaded insertion operator for the Graph object Visual Studio 15 (C++) reports,
(30): warning C4346: 'myGraph<T>::myGraphNode': dependent name is not a type
(30): note: prefix with 'typename' to indicate a type
(30): error C2061: syntax error: identifier 'myGraphNode'
(33): error C2805: binary 'operator <<' has too few parameters
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>::myGraphNode& gn)
adding the word typename to the second formal parameter
template <typename T>
ostream& operator<<(ostream& strm, typename const myGraph<T>::myGraphNode& gn)
The compiler generates the following error
(49): error C2679: binary '<<': no operator found which takes a right-hand operand of type 'const myGraph<int>::myGraphNode' (or there is no acceptable conversion)
I get the same error if I typename const .... or const typename ...
For completeness here is all the code somewhat simplified for this post.
Thanks for any help
#include <iostream>
#include <vector>
#include <string>
using namespace std;
typedef unsigned int uint;
template <typename T>
class myGraph {
public:
class myGraphNode {
public:
myGraphNode(T val = T());
T mData;
}; // end class myGraphNode
myGraph();
uint addGraphNode(T data);
vector<myGraphNode> mGraphNodes;
}; // end class myGraph
// myGraphNode
template <typename T>
myGraph<T>::myGraphNode::myGraphNode(T val) : mData(val) {}
template <typename T>
ostream& operator<<(ostream& strm, typename const myGraph<T>::myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
// myGraph
template <typename T>
myGraph<T>::myGraph() {}
template <typename T>
uint myGraph<T>::addGraphNode(T data) {
myGraph<T>::myGraphNode node(data);
mGraphNodes.push_back(node);
}
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>& g) {
for (uint i = 0; i < g.mGraphNodes.size(); ++i)
cout << g.mGraphNodes[i] << endl;
return strm;
} // end operator<<(...)
int main()
{
myGraph<int> g;
g.addGraphNode(3);
g.addGraphNode(5);
cout << g << endl;
return 0;
}
Firstly, the correct syntax for parameter declaration should be
template <typename T>
ostream& operator<<(ostream& strm, const typename myGraph<T>::myGraphNode& gn)
// ~~~~~ ~~~~~~~~
Refer here for more informations.
Secondly, with the above declaration, when trying to call it in operator<< for myGraph<T> like cout << g.mGraphNodes[i] << endl;, T can't be deduced because of non-deduced contexts):
The nested-name-specifier (everything to the left of the scope resolution operator ::) of a type that was specified using a qualified-id:
That means, you have to specify the template argument explicitly for it, e.g.
operator<<<T>(strm, g.mGraphNodes[i]);
// ~~~
But it's ugly. For your case, you can just implement operator<< for myGraph<T> like
template <typename T>
ostream& operator<<(ostream& strm, const myGraph<T>& g) {
for (uint i = 0; i < g.mGraphNodes.size(); ++i)
cout << g.mGraphNodes[i].mData << endl;
return strm;
}
BTW: You should give a return value for myGraph<T>::addGraphNode.
Template type deduction only matches patterns. It doesn't invert dependent types, because that (in the general case) is impossible.
The way to solve this problem is a technique I call Koenig operators.
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
Put this in the body of myGraphNode.
class myGraphNode {
public:
myGraphNode(T val = T());
T mData;
friend std::ostream& operator<<(std::ostream& strm, const myGraphNode& gn) {
strm << gn.mData << std::endl;
return strm;
}
}; // end class myGraphNode
This is a non-template operator injected into surrounding namespace (only) reachable via ADL. Which is fancy words for "it just works".
I have a pretty simple template which is a container which is an array of T. I am getting a syntax error :
container.h(7): error C2143: syntax error : missing ';' before '&'. I have tried removing the declaration there but then the error just skips over to the definition. Would appreciate any help.
EDIT: now i fixed the using namespace thing, but another error popped:
container.h(8): error C2975: 'Container' : invalid template argument for 'unnamed-parameter', expected compile-time constant expression
#include <typeinfo.h>
#include <assert.h>
#include <iostream>
#pragma once
using namespace std;
template <typename T, int> class Container;
template <typename T, int> ostream& operator<< <>(ostream &, const Container<T,int> &);
template<class T , int capacity=0> class Container
{
//using namespace std;
private:
T inside[capacity];
public:
Container()
{
}
~Container(void)
{
}
void set(const T &tType, int index)
{
assert(index>=0 && index<= capacity);
inside[index] = tType;
}
T& operator[](int index)
{
assert(index>=0 && index<= capacity);
return inside[index];
}
friend ostream& operator<< <>(ostream& out, const Container<T,int> c);
{
for(int i=0;i<sizeof(inside)/sizeof(T);i++)
out<<c.inside[i]<< "\t";
return out;
}
};
You probably want:
template <typename T, int N>
ostream& operator<<(ostream &, const Container<T,N> &);
// ^ here you need N, not int!
or, since you don't actually need the forward declaration, you can simply use this implementation in your class:
friend ostream& operator<<(ostream & out, const Container<T,capacity>& c)
{
for(int i=0;i<capacity;++i)
out<<c.inside[i]<< "\t";
return out;
}
You want something like:
template <typename T, int N>
friend ostream& operator<<(ostream & out, const Container<T,N>& c) {
for(int i=0;i<sizeof(inside)/sizeof(T);i++)
out<<c.inside[i]<< "\t";
return out;
}