error is in the title, here is the code :
Universe.hpp:
// Universe Class
// Damien MATTEI
#ifndef UNIVERSE_HPP
#define UNIVERSE_HPP
#include <algorithm> // used by Universe
#include <iostream>
#include <vector>
#include <list>
// Edge3D will include Point3D
#include "Edge3D.hpp"
#include "Vector3D.hpp"
#include "Object.hpp"
#include "debug.hpp"
using namespace std;
template <typename T> class Universe {
public:
// data
// name must be like containerTYPEptrCONTAINER_TYPEC (must end by a char like C or other only for macro reason (!))
// where TYPE is the element type contained in the container CONTAINER_TYPE
// example1: TYPE=Point3D , CONTAINER_TYPE=vector
std::vector< Point3D<T> *> containerPoint3DptrvectorC;
// example2: TYPE=Vector3D , CONTAINER_TYPE=vector
std::vector< Vector3D<T> *> containerVector3DptrvectorC;
// deprecated
// example3: TYPE=Edge3D , CONTAINER_TYPE=list
list < Point3D<T> *> containerPoint3DptrlistC;
list < Edge3D<T> *> containerEdge3DptrlistC;
// for deprecated compatibility in Vision3D.cpp
// the vertex
list < Point3D<T> > vertexList;
Universe();
~Universe();
// create a Point3D by checking if it already exist in the universe
template <typename ObjectType, typename... ParamTypes>
ObjectType & createPoint3DRefvectorC(ParamTypes ...args);
// create a Vector3D by checking if it already exist in the universe
template <typename ObjectType, typename... ParamTypes>
ObjectType & createVector3DRefvectorC(ParamTypes ...args);
// DEPRECATED (for tests)
Point3D<T> & createPoint3DReference(T x,T y,T z); // create a point by checking if it already exist
Point3D<T> & createPoint3Dref_BACKUP(T x,T y,T z); // backup because i created macro that builds functions now
// create a Point3D by checking if it already exist in the universe
template <typename ObjectType, typename... ParamTypes>
ObjectType & createPoint3DReflistC(ParamTypes ...args);
// create a Edge3D by checking if it already exist in the universe
template <typename ObjectType, typename... ParamTypes>
ObjectType & createEdge3DReflistC(ParamTypes ...args);
// create an object by checking if it already exist in the universe
// DEPRECATED
template <typename ObjectType, typename... ParamTypes>
ObjectType & createObjectRef(ParamTypes ...args);
Point3D<T> * createPoint3Dptr(T x,T y,T z); // create a point by checking if it already exist
void createCube(Point3D<T> &,T);
// for testing
template <typename myType,typename otherType>
myType GetMax (myType a, myType b);
template <typename U>
friend std::ostream& operator<< (ostream &, const Universe<U> &);
};
template <typename U> std::ostream& operator<< (ostream &, const Universe<U> &); // does not work !!!
#endif /* UNIVERSE_HPP */
Universe.cpp :
// Universe Class
// Damien MATTEI
#include "Universe.hpp"
// implementations
template <typename T> Universe<T>::Universe() {
#ifdef DISPLAY_CONSTRUCTOR
cout << "# Universe constructor # " << this << endl;
#endif
}
template <typename T> Universe<T>::~Universe() {
typename vector< Point3D<T> *>::iterator it;
for(it = containerPoint3DptrvectorC.begin(); it != containerPoint3DptrvectorC.end(); it++) {
cerr << "# Universe destructor # deleting a containerPoint3DptrvectorC" << endl;
delete *it;
}
typename list< Point3D<T> *>::iterator itLst;
for(itLst = containerPoint3DptrlistC.begin(); itLst != containerPoint3DptrlistC.end(); itLst++) {
cerr << "# Universe destructor # deleting a containerPoint3DptrlistC" << endl;
delete *itLst;
}
#ifdef DISPLAY_CONSTRUCTOR
cout << "# Universe destructor # " << this << endl;
#endif
}
// for testing
template <typename T>
template <typename myType,typename otherType>
myType Universe<T>::GetMax (myType a, myType b) {
// otherType i= 7; //useless
return (a>b?a:b);
}
#define CREATE_OBJECT_TEMPLATED(TYPE,TYPE_CONTAINER) \
/* create an object by checking if it already exist in the universe */ \
template <typename T> \
template <typename ObjectType, typename... ParamTypes> \
\
ObjectType & Universe<T>::create##TYPE##Ref##TYPE_CONTAINER##C(ParamTypes ...args) { \
\
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<>" << endl;) \
\
ObjectType & object = *(new ObjectType(std::forward<ParamTypes>(args) ...));\
\
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : std::find_if ... " << endl;)\
\
/* i check unicity of the object in Universe i.e to save memory and speed */ \
/* i do not want to have two mathematically identical 3D objects */ \
typename TYPE_CONTAINER < ObjectType *>::iterator iterOBJECTptr = \
std::find_if(container##TYPE##ptr##TYPE_CONTAINER##C.begin(), container##TYPE##ptr##TYPE_CONTAINER##C.end(), \
/* lambda in C++ */ \
[&object](ObjectType * object_ptr_lambda_param) { \
ObjectType & object_lambda_param = *object_ptr_lambda_param; \
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : in Lambda" << endl;) \
return object_lambda_param == object; \
} \
); \
\
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : bool found ... " << endl;) \
bool found = (iterOBJECTptr != container##TYPE##ptr##TYPE_CONTAINER##C.end()); \
\
\
if (found) { \
\
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : *iterOBJECTptr " << *iterOBJECTptr << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : **iterOBJECTptr " << **iterOBJECTptr << endl << endl;) \
\
delete &object; \
\
return **iterOBJECTptr; /* return the pointer OBJECT */ \
\
} \
else { /* we have to add the point to the universe */ \
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : NOT found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "Ref" #TYPE_CONTAINER "C<> : container" #TYPE "ptr" #TYPE_CONTAINER "C.push_back(&object);" << endl << endl;) \
\
container##TYPE##ptr##TYPE_CONTAINER##C.push_back(&object); \
\
return object; \
} \
\
}
CREATE_OBJECT_TEMPLATED(Point3D,vector)
CREATE_OBJECT_TEMPLATED(Vector3D,vector)
// DEPRECATED
// this create the Template only for Point3D (not a particular instance for float by example)
// example of call : univ.createPoint3DRef<Point3D<float>,float,float,float>(1,0,0);
CREATE_OBJECT_TEMPLATED(Point3D,list)
CREATE_OBJECT_TEMPLATED(Edge3D,list)
// create an object by checking if it already exist in the universe
// warning: works only with Point3D as the container containerPoint3DptrlistC is statically defined
// DEPRECATED i suppose
template <typename T>
template <typename ObjectType, typename... ParamTypes>
ObjectType & Universe<T>::createObjectRef(ParamTypes ...args) {
DEBUG(cerr << "Universe<T>::createObjectRef" << endl;)
ObjectType & object = *(new ObjectType(std::forward<ParamTypes>(args) ...));
//ObjectType & object = *(new ObjectType());
DEBUG(cerr << "Universe<T>::createObjectRef : std::find_if ... " << endl;)
// i check unicity of the point in Universe i.e to save memory and speed
// i do not want to have two mathematically identical 3D points
typename list< ObjectType *>::iterator iterOBJECTptr =
std::find_if(containerPoint3DptrlistC.begin(), containerPoint3DptrlistC.end(),
// lambda in C++
[&object](ObjectType * object_ptr_lambda_param) {
ObjectType & object_lambda_param = *object_ptr_lambda_param;
DEBUG(cerr << "Universe<T>::createObjectRef : in Lambda" << endl;)
return object_lambda_param == object;
}
);
DEBUG(cerr << "Universe<T>::createObjectRef : bool found ... " << endl;)
bool found = (iterOBJECTptr != containerPoint3DptrlistC.end());
if (found) {
DEBUG(cerr << "Universe<T>::createObjectRef : found ... " << endl;)
DEBUG(cerr << "Universe<T>::createObjectRef : *iterOBJECTptr " << *iterOBJECTptr << endl;)
DEBUG(cerr << "Universe<T>::createObjectRef : **iterOBJECTptr " << **iterOBJECTptr << endl;)
delete &object;
return **iterOBJECTptr; // return the pointer to OBJECT
}
else { // we have to add the point to the universe
DEBUG(cerr << "Universe<T>::createObjectRef : NOT found ... " << endl;)
DEBUG(cerr << "Universe<T>::createObjectRef : containerPoint3DptrlistC.push_back(&object);" << endl;)
containerPoint3DptrlistC.push_back(&object);
return object;
}
}
// create a point by checking if it already exists in the universe
// DEPRECATED
template<typename T> Point3D<T> & Universe<T>::createPoint3Dref_BACKUP(T x,T y,T z) {
DEBUG(cerr << "Universe<T>::createPoint3Dref" << endl;)
Point3D<T> & pt3d = *(new Point3D<T>(x,y,z));
DEBUG(cerr << "Universe<T>::createPoint3Dref : std::find_if ... " << endl;)
// i check unicity of the point in Universe i.e to save memory and speed
// i do not want to have two mathematically identical 3D points
typename list< Point3D<T> *>::iterator iterP3Dptr =
std::find_if(containerPoint3DptrlistC.begin(), containerPoint3DptrlistC.end(),
// lambda in C++
[&pt3d](Point3D<T> * pt3d_ptr_lambda_param) {
Point3D<T> & pt3d_lambda_param = *pt3d_ptr_lambda_param;
DEBUG(cerr << "Universe<T>::createPoint3Dref : in Lambda" << endl;)
//return *pt3d_ptr_lambda_param == pt3d;
return pt3d_lambda_param == pt3d;
}
);
DEBUG(cerr << "Universe<T>::createPoint3Dref : bool found ... " << endl;)
bool found = (iterP3Dptr != containerPoint3DptrlistC.end());
if (found) {
DEBUG(cerr << "Universe<T>::createPoint3Dref : found ... " << endl;)
DEBUG(cerr << "Universe<T>::createPoint3Dref : *iterP3Dptr " << *iterP3Dptr << endl;)
DEBUG(cerr << "Universe<T>::createPoint3Dref : **iterP3Dptr " << **iterP3Dptr << endl;)
delete &pt3d;
//return static_cast<Point3D<T> &> (*iterP3Dptr); // return the pointer to Point3D
//return reinterpret_cast<Point3D<T> &> (*iterP3Dptr); // return the pointer to Point3D
//return static_cast<Point3D<T> &> (**iterP3Dptr); // return the pointer to Point3D
return **iterP3Dptr; // return the pointer to Point3D
}
else { // we have to add the point to the universe
DEBUG(cerr << "Universe<T>::createPoint3Dptr : NOT found ... " << endl;)
DEBUG(cerr << "Universe<T>::createPoint3Dref : containerPoint3DptrlistC.push_back(&pt3d);" << endl;)
containerPoint3DptrlistC.push_back(&pt3d);
return pt3d;
}
}
// create an object by checking if it already exist in the universe
// DEPRECATED
#define CREATE_OBJECT(FUNCTION_NAME,TYPE,CONTAINER,PARENTHESIS_ARGS,TYPED_PARAMS...) template<typename T> TYPE & Universe<T>::FUNCTION_NAME(TYPED_PARAMS) { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref" << endl;) \
TYPE & object = *(new TYPE PARENTHESIS_ARGS); \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : std::find_if ... " << endl;) \
typename list< TYPE *>::iterator iterObjectptr = \
std::find_if( CONTAINER.begin(), CONTAINER.end(), \
[&object](TYPE * object_ptr_lambda_param) { \
TYPE & object_lambda_param = *object_ptr_lambda_param; \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : in Lambda" << endl;) \
return object_lambda_param == object; \
} \
); \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : bool found ... " << endl;) \
bool found = (iterObjectptr != CONTAINER.end()); \
if (found) { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : *iterObjectptr " << *iterObjectptr << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : **iterObjectptr " << **iterObjectptr << endl;) \
delete &object; \
return **iterObjectptr; \
} \
else { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ptr : NOT found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : CONTAINER.push_back(object_ptr);" << endl;) \
CONTAINER.push_back(&object); \
return object; \
} \
}
//CREATE_OBJECT(createPoint3Dref,Point3D<T>,containerPoint3DptrlistC,(x,y,z),T x,T y,T z);
// create an object by checking if it already exist in the universe
// this a better version than CREATE_OBJECT, this macro use less parameters
#define CREATE_OBJECT_TYPE(TYPE,CONTAINER,PARENTHESIS_ARGS,TYPED_PARAMS...) template<typename T> TYPE<T> & Universe<T>::create##TYPE##ref(TYPED_PARAMS) { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref" << endl;) \
TYPE<T> & object = *(new TYPE<T> PARENTHESIS_ARGS); \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : std::find_if ... " << endl;) \
typename list< TYPE<T> *>::iterator iterObjectptr = \
std::find_if( CONTAINER.begin(), CONTAINER.end(), \
[&object](TYPE<T> * object_ptr_lambda_param) { \
TYPE<T> & object_lambda_param = *object_ptr_lambda_param; \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : in Lambda" << endl;) \
return object_lambda_param == object; \
} \
); \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : bool found ... " << endl;) \
bool found = (iterObjectptr != CONTAINER.end()); \
if (found) { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : *iterObjectptr " << *iterObjectptr << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : **iterObjectptr " << **iterObjectptr << endl;) \
delete &object; \
return **iterObjectptr; \
} \
else { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ptr : NOT found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "ref : CONTAINER.push_back(object_ptr);" << endl;) \
CONTAINER.push_back(&object); \
return object; \
} \
}
// DEPRECATED
//#define CONCATENATE(x , y) x##y
//CREATE_OBJECT_TYPE(Point3D,containerPoint3DptrlistC,(x,y,z),T x,T y,T z);
// create an object by checking if it already exist in the universe
// this another better version than CREATE_OBJECT, this macro use again less parameters
// DEPRECATED
#define CREATE_OBJECT_TYPED(TYPE,PARENTHESIS_ARGS,TYPED_PARAMS...)\
template<typename T> TYPE<T> & Universe<T>::create##TYPE##Reference(TYPED_PARAMS) { \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference" << endl;) \
TYPE<T> & object = *(new TYPE<T> PARENTHESIS_ARGS); \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : std::find_if ... " << endl;) \
typename list< TYPE<T> *>::iterator iterObjectptr = \
std::find_if( container##TYPE##ptrlistC.begin(), container##TYPE##ptrlistC.end(), \
[&object](TYPE<T> * object_ptr_lambda_param) { \
TYPE<T> & object_lambda_param = *object_ptr_lambda_param; \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : in Lambda" << endl;) \
return object_lambda_param == object; \
} \
); \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : bool found ... " << endl;) \
bool found = (iterObjectptr != container##TYPE##ptrlistC.end()); \
if (found) { \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : *iterObjectptr " << *iterObjectptr << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : **iterObjectptr " << **iterObjectptr << endl;) \
delete &object; \
return **iterObjectptr; \
} \
else { \
DEBUG(cerr << "Universe<T>::create" #TYPE "ptr : NOT found ... " << endl;) \
DEBUG(cerr << "Universe<T>::create" #TYPE "Reference : container???.push_back(object_ptr);" << endl;) \
container##TYPE##ptrlistC.push_back(&object); \
return object; \
} \
}
// example: univ.createPoint3DReference(1,0,0);
CREATE_OBJECT_TYPED(Point3D,(x,y,z),T x,T y,T z);
// create a point by checking if it already exist in the universe
template<typename T> Point3D<T> * Universe<T>::createPoint3Dptr(T x,T y,T z) {
DEBUG(cerr << "Universe<T>::createPoint3Dptr" << endl;)
Point3D<T> * pt3d_ptr = new Point3D<T>(x,y,z);
Point3D<T> & pt3d = *pt3d_ptr;
DEBUG(cerr << "Universe<T>::createPoint3Dptr : std::find_if ... " << endl;)
// i check unicity of the point in Universe i.e to save memory and speed
// i do not want to have two mathematically identical 3D points
typename list< Point3D<T> *>::iterator iterP3Dptr =
std::find_if(containerPoint3DptrlistC.begin(), containerPoint3DptrlistC.end(),
// lambda in C++
[&pt3d](Point3D<T> * pt3d_ptr_lambda_param) {
Point3D<T> & pt3d_lambda_param = *pt3d_ptr_lambda_param;
DEBUG(cerr << "Universe<T>::createPoint3Dptr : in Lambda" << endl;)
//return *pt3d_ptr_lambda_param == pt3d;
return pt3d_lambda_param == pt3d;
}
);
DEBUG(cerr << "Universe<T>::createPoint3Dptr : bool found ... " << endl;)
bool found = (iterP3Dptr != containerPoint3DptrlistC.end());
if (found) {
DEBUG(cerr << "Universe<T>::createPoint3Dptr : found ... " << endl;)
DEBUG(cerr << "Universe<T>::createPoint3Dptr : *iterP3Dptr " << *iterP3Dptr << endl;)
DEBUG(cerr << "Universe<T>::createPoint3Dptr : **iterP3Dptr " << **iterP3Dptr << endl;)
delete pt3d_ptr;
//return static_cast<Point3D<T> &> (*iterP3Dptr); // return the pointer to Point3D
//return reinterpret_cast<Point3D<T> &> (*iterP3Dptr); // return the pointer to Point3D
//return static_cast<Point3D<T> &> (**iterP3Dptr); // return the pointer to Point3D
return *iterP3Dptr; // return the pointer to Point3D
}
else { // we have to add the point to the universe
DEBUG(cerr << "Universe<T>::createPoint3Dptr : NOT found ... " << endl;)
DEBUG(cerr << "Universe<T>::createPoint3Dptr : containerPoint3DptrlistC.push_back(pt3d_ptr);" << endl;)
containerPoint3DptrlistC.push_back(pt3d_ptr);
return pt3d_ptr;
}
}
// params: point, edge length
template<typename T> void Universe<T>::createCube(Point3D<T> & p,T s) {
// horizontal edges
Point3D<T> & p2 = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x+s,p.y,p.z); // bottom ,right x
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p,p2);
Point3D<T> & p3 = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x+s,p.y+s,p.z); // bottom ,right x,left y
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p2,p3);
Point3D<T> & p4 = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x,p.y+s,p.z); // bottom ,left y
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p3,p4);
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p,p4);
Point3D<T> & ptop = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x,p.y,p.z+s);
Point3D<T> & p2top = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x+s,p.y,ptop.z); // top ,right x
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p,p2top);
Point3D<T> & p3top = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x+s,p.y+s,ptop.z); // top ,right x,left y
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p2top,p3top);
Point3D<T> & p4top = createPoint3DReflistC<Point3D<T>,T,T,T>(p.x,p.y+s,ptop.z); // top ,left y
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p3top,p4top);
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(ptop,p4top);
// vertical edges
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p,ptop);
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p2,p2top);
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p3,p3top);
createEdge3DReflistC<Edge3D<T>,Point3D<T> &,Point3D<T> &>(p4,p4top);
}
// DEPRECATED
//template Point3D<float> & Universe<float>::createObjectRef(float,float,float) ; // works too
template Point3D<float> & Universe<float>::createObjectRef<Point3D<float>,float,float,float>(float,float,float) ;
//template int Universe<float>::createObjectRef<int,float,float,float>(float,float,float) ;
template <typename U>
std::ostream& operator<< (std::ostream &out, Universe<U> &u)
{
out << "Universe :"
<< &u
<< " "
;
return out;
}
template class Universe<float>;
// for tests
//template int Universe<float>::GetMax( int,int ) ; // works too
template int Universe<float>::GetMax<int,float>( int,int );
// call by : univ.createPoint3DReflistC<Point3D<float>,float,float,float>(1,0,0);
template Point3D<float> & Universe<float>::createPoint3DReflistC<Point3D<float>,float,float,float>(float,float,float) ;
template Edge3D<float> & Universe<float>::createEdge3DReflistC<Edge3D<float>,Point3D<float>&,Point3D<float>&>(Point3D<float>&,Point3D<float>&) ;
template Point3D<float> & Universe<float>::createPoint3DRefvectorC<Point3D<float>,float,float,float>(float,float,float) ;
template Vector3D<float> & Universe<float>::createVector3DRefvectorC<Vector3D<float>,float,float,float>(float,float,float) ;
template std::ostream& operator<< (std::ostream &, const Universe<float> &); // does not work
(base) albedo-2:vision3D mattei$ make COMPILING Universe.cpp g++ -c -o Universe.o Universe.cpp -Wall -std=c++17 -I. -DDEBUG_BUILD -DDISPLAY_CONSTRUCTOR -DCHECK_MEMORY Universe.cpp:468:25: error: explicit instantiation of undefined function template 'operator<<' template std::ostream& operator<< (std::ostream &, const Universe &); // does not work ^ ./Universe.hpp:109:39: note: explicit instantiation refers here template std::ostream& operator<< (ostream &, const Universe &); // does not work !!! ^ 1 error generated. make: *** [Universe.o] Error 1