errors = templates * friends;

F

fabio de francesco

Hello,

I'm just joking with the Subject, but I really don't know how to make
a synthesis of two questions about some code I'm trying to write.

In the following I post this little code, with "..." meaning what I
think can be omitted for brevity.


// file database.h
....
template <typename T>
class DataBase
{
public:
DataBase();
...
private:
...
void run();
ostream& print( ostream & );
friend ostream& operator<<(ostream &out, DataBase<T> &db)
{ return db.print( out ); }
};
....

// file database.cpp
....
template <typename T>
DataBase<T>::DataBase()
{...}
template<typename T>
void DataBase<T>::run()
{...}
....

// file usedb.cpp
....
#include "database.h"
#include "person.h"
....
int main()
{
DataBase<Person> db; // usedb.cpp:11 (error)
...
return 0;
}

The first problem is that the linker editor ( I suppose ) comes out
with this error:

/database/src/usedb.cpp:11: undefined reference to
`DataBase<Person>::DataBase[in-charge]()'

I got the same error also if I try to instantiate 'DataBase<int> db'.

This is not the first time I use templates but I've never seen such an
error.
I'm sure I am doing some stupid thing.

The second problem arises if I try to extract the implementation code
of the friend overloaded operator "<<" from the class definition (
database.h ) to be put in the implementation file ( database.cpp ).

// file DataBase.h
....
friend ostream& operator<<( ostream &out, DataBase<T> &db );
....

// file DataBase.cpp
....
template<typename T>
ostream& operator<<( ostream &out, DataBase<T> &db )
{ return db.print( out ); }
....

Here the errors, while compiling:

/src/database.h:31: warning: friend declaration `std::eek:stream&
operator<<(std::eek:stream&, DataBase<T>&)' declares a non-template
function
/src/database.h:31: warning: (if this is not what you intended, make
sure the function template has already been declared and add <> after
the function name here) -Wno-non-template-friend disables this warning

That's all. I want to thank in advance everyone who will explain what
kind of errors I put in the code. I would appreciate also any partial
reply on the first topic that is the most important for me.

Ciao,

Fabio De Francesco.
 
R

Rob Williscroft

fabio de francesco wrote in
in comp.lang.c++:
Hello,

I'm just joking with the Subject, but I really don't know how to make
a synthesis of two questions about some code I'm trying to write.

In the following I post this little code, with "..." meaning what I
think can be omitted for brevity.


// file database.h
...
template <typename T>
class DataBase
{
public:
DataBase();
...
private:
...
void run();
ostream& print( ostream & );

This is a non-template function, you can't define it outside of the
class-template, as you try to do later.
friend ostream& operator<<(ostream &out, DataBase<T> &db)
{ return db.print( out ); }
};
...

Here's your first problem, templates need to be defined in the
the same compilation that uses them, put these defenition's in
your header file.
// file database.cpp
...
template <typename T>
DataBase<T>::DataBase()
{...}
template<typename T>
void DataBase<T>::run()
{...}
...
[snip]

Here's an example of a template friend (note all the cruft):

#include <iostream>
#include <ostream>


/* Forward declare X, so we can forward declare operator <<
*/
template < typename T > struct X;
template < typename T >
std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );


template < typename T >
struct X
{
friend /* Note the <> */
std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
};

/* declaration/defenition - in the *header*
*/
template < typename T >
std::eek:stream & operator << ( std::eek:stream &os, X< T > const & )
{
os << "friend\n";
return os;
}

int main()
{
X< int > x;
std::cout << x;
}

Alternativly do it like this:

#include <iostream>
#include <ostream>

template < typename T >
struct X
{
private:
void printon( std::eek:stream &os ) const;
friend std::eek:stream & operator << ( std::eek:stream &os, X< T > const &x )
{
x.printon( os );
return os;
}
};


template < typename T >
void X< T >::printon( std::eek:stream &os ) const
{
os << "friend\n";
}

int main()
{
X< int > x;
std::cout << x;
}

Slightly less cruft :).

Rob.
 
J

John Harrison

Here's an example of a template friend (note all the cruft):

#include <iostream>
#include <ostream>


/* Forward declare X, so we can forward declare operator <<
*/
template < typename T > struct X;
template < typename T >
std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );

This confuses me, I know what to do but I still don't understand why.

Why is it necessary to forward declare the operator in this case?

john
 
R

Rob Williscroft

John Harrison wrote in in
comp.lang.c++:
This confuses me, I know what to do but I still don't understand why.

Why is it necessary to forward declare the operator in this case?

Because the friend /statement/ in this:

template < typename T >
struct X
{
friend /* Note the <> */
std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
};

isn't a declaration.

The following example contains a declaration but its to generic, i.e. it
grants friendship to widely, not that that is ever a /real/ problem.

#include <iostream>
#include <ostream>

template < typename T >
struct Y
{
template < typename U >
friend
std::eek:stream &operator << ( std::eek:stream &os, Y< U > const & );

};

template < typename T >
std::eek:stream & operator <<( std::eek:stream &os, Y< T > const & )
{
os << "friend\n";
return os;
}

int main()
{
Y< int > y;
std::cout << y;
}

Rob.
 
J

John Harrison

Rob Williscroft said:
John Harrison wrote in in
comp.lang.c++:


Because the friend /statement/ in this:

template < typename T >
struct X
{
friend /* Note the <> */
std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
};

isn't a declaration.

I think I'd quibble with your terminology. I guess (if I understand you
right) that I'd say although the above does declare friendship it doesn't
declare the function template itself. Which thinking about it seems
reasonable enough, it doesn't look anything like a function template
declaration.

Thanks, John
 
F

fabio de francesco

Rob Williscroft said:
Here's your first problem, templates need to be defined in the
the same compilation that uses them, put these defenition's in
your header file.
// file database.cpp
...
template <typename T>
DataBase<T>::DataBase()
{...}
template<typename T>
void DataBase<T>::run()
{...}
... [snip]
....
/* Forward declare X, so we can forward declare operator <<
*/
template < typename T > struct X;
template < typename T >
std::eek:stream & operator << ( std::eek:stream &os, X< T > const & );


template < typename T >
struct X
{
friend /* Note the <> */
std::eek:stream & operator << <>( std::eek:stream &os, X< T > const & );
};

/* declaration/defenition - in the *header*
*/
template < typename T >
std::eek:stream & operator << ( std::eek:stream &os, X< T > const & )
{
os << "friend\n";
return os;
}

int main()
{
X< int > x;
std::cout << x;
}

Thank you Rob.

I actually solved the problem by using the forward declarations plus
the "<>" notation as you wrote, but fortunately I wasn't to much
inclined to put the definitions of the functions ( that are a thousand
of lines of code ) into the header file.

With this is my mind I found a way to keep untouched the code in
database.cpp by adding pre-declarations of the possible use of
template parameters ( I'm not sure I can name them this way ),

So I added ( in database.cpp ):

#include "person.h"
template DataBase<Person>;

#include "myfriends"
template DataBase<MyFriends>;

and so on. Now I can ( in usedb.cpp ) instantiate

DataBase<Person> dbPerson;
DataBase<MyFriends> dbMyFriends;

with no more linker editor errors.

Your advice was enough to make me put that friend function
implementation in database.cpp too, without any further modification.

Ciao,
Fabio De Francesco.
 
W

Wouter Lievens

fabio de francesco said:
Hello,

I'm just joking with the Subject, but I really don't know how to make
a synthesis of two questions about some code I'm trying to write.

In the following I post this little code, with "..." meaning what I
think can be omitted for brevity.


// file database.h
...
template <typename T>
class DataBase
{
public:
DataBase();
...
private:
...
void run();
ostream& print( ostream & );
friend ostream& operator<<(ostream &out, DataBase<T> &db)
{ return db.print( out ); }
};
...

// file database.cpp
...
template <typename T>
DataBase<T>::DataBase()
{...}
template<typename T>
void DataBase<T>::run()
{...}
...

// file usedb.cpp
...
#include "database.h"
#include "person.h"
...
int main()
{
DataBase<Person> db; // usedb.cpp:11 (error)
...
return 0;
}

The first problem is that the linker editor ( I suppose ) comes out
with this error:

/database/src/usedb.cpp:11: undefined reference to
`DataBase<Person>::DataBase[in-charge]()'

I got the same error also if I try to instantiate 'DataBase<int> db'.

This is not the first time I use templates but I've never seen such an
error.
I'm sure I am doing some stupid thing.

The second problem arises if I try to extract the implementation code
of the friend overloaded operator "<<" from the class definition (
database.h ) to be put in the implementation file ( database.cpp ).

// file DataBase.h
...
friend ostream& operator<<( ostream &out, DataBase<T> &db );
...

// file DataBase.cpp
...
template<typename T>
ostream& operator<<( ostream &out, DataBase<T> &db )
{ return db.print( out ); }
...

Here the errors, while compiling:

/src/database.h:31: warning: friend declaration `std::eek:stream&
operator<<(std::eek:stream&, DataBase<T>&)' declares a non-template
function
/src/database.h:31: warning: (if this is not what you intended, make
sure the function template has already been declared and add <> after
the function name here) -Wno-non-template-friend disables this warning

That's all. I want to thank in advance everyone who will explain what
kind of errors I put in the code. I would appreciate also any partial
reply on the first topic that is the most important for me.

Ciao,

Fabio De Francesco.


Templates that will be used in multiple files have to be implemented in the
header file.
That's all, I think.
 
F

fabio de francesco

Wouter Lievens said:
Templates that will be used in multiple files have to be implemented in the
header file.
That's all, I think.

I think, with all respect, you'd better read all the thread, in which
more solutions have been found, before stating something that has been
outdone a few days ago (without implementing templates in the header
file).

I don't want to be polemical, it is just that someone can rely on what
is added at the end of a thread by thinking that some steps forward
have been taken after days of discussion.

Regards,

Fabio De Francesco
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,768
Messages
2,569,575
Members
45,053
Latest member
billing-software

Latest Threads

Top