Board index » cppbuilder » About friend template function

About friend template function


2006-02-22 12:47:59 AM
cppbuilder58
Hi
I have an interface file with template class definition. This class
definition contains a friend function
friend ostream & operator<<( ostream & outs, const List<ItemType>&
theList );
Also I have a realization file with the following function definition
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;
return outs;
}
And at last in main program there is
cout << "first_list = \n" << first_list;
But when I build the corresponding project (BCB 5.0) I get linker error
[Linker Error] Unresolved external
"listsavitch::operator<<(std::basic_ostream(char, std::....
What is wrong?
Vladimir Grigoriev
 
 

Re:About friend template function

Vladimir Grigoriev wrote:
Quote
Hi
I have an interface file with template class definition. This class
definition contains a friend function

friend ostream & operator<<( ostream & outs, const List<ItemType>&
theList );
That friend declaration is for a *non-template* function. E.g., for
List<int>, that declares the non-template function "ostream &
operator<<( ostream & outs, const List<int>& theList)" to be a friend.
It also declares that function to be visible via argument dependent
lookup on List<int>.
Quote
Also I have a realization file with the following function definition

template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;

return outs;
}
That's independent of the friend declaration above.
Quote
And at last in main program there is

cout << "first_list = \n" << first_list;
That finds the non-template function declared in the friend declaration
via ADL as well as the template defined above, and picks the
non-template since non-templates always beat templates in overload
resolution.
Quote
But when I build the corresponding project (BCB 5.0) I get linker error

[Linker Error] Unresolved external
"listsavitch::operator<<(std::basic_ostream(char, std::....

What is wrong?
You never defined the non-template friend. There are two solutions.
1. Define the non-template functions:
friend ostream & operator<<( ostream & outs, const List<ItemType>&
theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;
return outs;
}
Note that the only way to do this is to define the function inline
inside the class body.
2. Make the relevent template specialization a friend, and don't declare
the non-template:
//fwd declarations are necessary:
template <typename ItemType>
class List;
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList);
//you could put operator<< definition here, before List definition,
//thanks to two phase name lookup. I haven't, for clarity.
template <typename ItemType>
class List
{
//...
//Note the <ItemType>on the line below:
friend ostream & operator<< <ItemType>( ostream & outs, const
List<ItemType>& theList);
};
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList)
{
//put definition here as before.
}
1 is good in that it is supported even by quite old compilers, whereas 2
requires a reasonably standards compliant compiler.
Tom
 

Re:About friend template function

"Vladimir Grigoriev" < XXXX@XXXXX.COM >wrote:
Quote
I have an interface file with template class definition. This class
definition contains a friend function
[snip]
Quote
Also I have a realization file with the following function definition
[snip]
Quote
And at last in main program there is

cout << "first_list = \n" << first_list;

But when I build the corresponding project (BCB 5.0) I get linker error
Did you include the implementation file ('realization file') in the file
that actually contained that statement?
Under the currently available template model (but see exception below),
the compiler will instantiate the template function code only when it
sees the template being used _AND_ it knows what the template definition
(implementation) is. If it sees it used, but doesn't know the
implementation, it will just insert a link to an external
implementation. And of course, if it sees the implementation without any
usage, it won't generate the code (after all, with gazillions of
possible types is could instantiate it round, that would take a while to
do them all).
So, there are two strategies. One, put the template definition in one
source file, and in that same file explicitly use all the instantiation
types you want. Two, put the template definition into a header file,
probably included from the declaration (interface) file. This will be a
little slower, but a lot more reliable.
The exception is when the compiler actually implements export templates.
No Borland compiler does, and very few others do either.
Alan Bellingham
--
ACCU Conference 2006 - 19-22 April, Randolph Hotel, Oxford, UK
 

{smallsort}

Re:About friend template function

Hi Alan
The main file is
#include <iostream>
#include <conio.h>
#pragma hdrstop
#include "list.h" // interface
#include "list.cpp" // realisation (also includes list.h)
//--------------------------------------------------------------------------
-
using namespace std;
using namespace listsavitch;
#pragma argsused
int main( int argc, char* argv[] )
{
...
cout << "first_list = \n" << first_list;
...
The interface file
namespace listsavitch
{
template<typename ItemType>
class List
{
...
friend ostream & operator<<( ostream & outs,
const List<ItemType>& theList );
...
The realisation file
using namespace std;
namespace listsavitch
{
...
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;
return outs;
}
} // listsavitch
This example is taken from a Walter Savitch book on C++.
Vladimir Grigoriev
"Alan Bellingham" < XXXX@XXXXX.COM >wrote in message
Quote
"Vladimir Grigoriev" < XXXX@XXXXX.COM >wrote:

>I have an interface file with template class definition. This class
>definition contains a friend function

[snip]

>Also I have a realization file with the following function definition

[snip]

>And at last in main program there is
>
>cout << "first_list = \n" << first_list;
>
>But when I build the corresponding project (BCB 5.0) I get linker error

Did you include the implementation file ('realization file') in the file
that actually contained that statement?

Under the currently available template model (but see exception below),
the compiler will instantiate the template function code only when it
sees the template being used _AND_ it knows what the template definition
(implementation) is. If it sees it used, but doesn't know the
implementation, it will just insert a link to an external
implementation. And of course, if it sees the implementation without any
usage, it won't generate the code (after all, with gazillions of
possible types is could instantiate it round, that would take a while to
do them all).

So, there are two strategies. One, put the template definition in one
source file, and in that same file explicitly use all the instantiation
types you want. Two, put the template definition into a header file,
probably included from the declaration (interface) file. This will be a
little slower, but a lot more reliable.

The exception is when the compiler actually implements export templates.
No Borland compiler does, and very few others do either.

Alan Bellingham
--
ACCU Conference 2006 - 19-22 April, Randolph Hotel, Oxford, UK
 

Re:About friend template function

"Vladimir Grigoriev" < XXXX@XXXXX.COM >writes:
Quote
I have an interface file with template class definition. This class
definition contains a friend function

friend ostream & operator<<( ostream & outs, const List<ItemType>&
theList );
This declares a non-template function.
Quote
Also I have a realization file with the following function definition

template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;

return outs;
}
This defines a function template.
Quote
And at last in main program there is

cout << "first_list = \n" << first_list;

But when I build the corresponding project (BCB 5.0) I get linker error

[Linker Error] Unresolved external
"listsavitch::operator<<(std::basic_ostream(char, std::....

What is wrong?
The declaration of the non-template function. Change it into a
specialization of a function template, i.e. something like:
template <typename ItemType>
class List;
template <typename ItemType>
std::ostream & operator<<(std::ostream &, List<ItemType>const &);
template <typename ItemType>
class List
{
// ... your List implementation
// replace the friend declaration with this one:
friend std::ostream &operator<< <>(std::ostream &, List<ItemType>const &);
};
Note the added "<>" which cause the specialization of operator << for
ItemType to be a friend of List<ItemType>.
 

Re:About friend template function

Hi Tom
Quote
1. Define the non-template functions:

friend ostream & operator<<( ostream & outs, const List<ItemType>&
theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;

return outs;
}

Note that the only way to do this is to define the function inline
inside the class body.
If I do as you have pointed (1) I get another error
[C++ Error] list.h...E2316 '<<' is not a member of 'listsavitch'
#include <iostream>
using namespace std;
namespace listsavitch
{
template<typename ItemType>
class List
{
public:
List( int max );
~List();
int length() const;
void add( ItemType new_item );
bool full() const;
void erase();
friend ostream & operator<<( ostream & outs,
const List<ItemType>& theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;
return outs;
}
private:
ItemType *item;
int max_length;
int current_length;
}; // class List
} // namespace listsavitch
 

Re:About friend template function

Hi Tom
I have also tried the second option as you have adviced.
Here the code
Interface file
#include <iostream>
using namespace std;
namespace listsavitch
{
template <typename ItemType>
class List;
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList);
template<typename ItemType>
class List
{
public:
List( int max );
~List();
int length() const;
void add( ItemType new_item );
bool full() const;
void erase();
template <typename ItemType>
friend ostream & operator<< <ItemType>( ostream & outs,
const List<ItemType>& theList );
private:
ItemType *item;
int max_length;
int current_length;
}; // class List
} // namespace listsavitch
Realization file
using namespace std;
namespace listsavitch
{
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList )
{
for ( int i = 0; i < theList.current_length; i++ )
outs << theList.item[i] << endl;
return outs;
}
} // listsavitch
I get errors
[C++ Error] ...E2247 'List<int>::current_length' is not accessible
[C++ Error]....E2247 'List<int>::item' is not accessible
These errors poitn to the realization.
Vladimir Grigoriev
 

Re:About friend template function

Vladimir Grigoriev wrote:
Quote
Hi Tom
I have also tried the second option as you have adviced.
Here the code
template<typename ItemType>
class List
{
public:
List( int max );
~List();
int length() const;
void add( ItemType new_item );
bool full() const;
void erase();
template <typename ItemType>
Delete the above line.
Quote
friend ostream & operator<< <ItemType>( ostream & outs,
const List<ItemType>& theList );
Tom
 

Re:About friend template function

Thank you Tom.
Now it works.
Vladimir Grigoriev
"Tom Widmer" < XXXX@XXXXX.COM >wrote in message
Quote
Vladimir Grigoriev wrote:
>Hi Tom
>I have also tried the second option as you have adviced.
>Here the code

>template<typename ItemType>
>class List
>{
>public:
>List( int max );
>~List();
>int length() const;
>void add( ItemType new_item );
>bool full() const;
>void erase();
>template <typename ItemType>

Delete the above line.

>friend ostream & operator<< <ItemType>( ostream & outs,
>const List<ItemType>& theList );

Tom
 

Re:About friend template function

I don't only understand the syntax
friend ostream & operator<< <ItemType>( ostream & outs, const List<ItemType>
& theList );
Why there is present <ItemType>after operator << ? What is the meaning of
it?
While defining the template function
template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList);
we don't include <ItemType>after operator<<
Vladimir Grigoriev
"Tom Widmer" < XXXX@XXXXX.COM >wrote in message
Quote
Vladimir Grigoriev wrote:
>Hi Tom
>I have also tried the second option as you have adviced.
>Here the code

>template<typename ItemType>
>class List
>{
>public:
>List( int max );
>~List();
>int length() const;
>void add( ItemType new_item );
>bool full() const;
>void erase();
>template <typename ItemType>

Delete the above line.

>friend ostream & operator<< <ItemType>( ostream & outs,
>const List<ItemType>& theList );

Tom
 

Re:About friend template function

Vladimir Grigoriev wrote:
Quote
I don't only understand the syntax

friend ostream & operator<< <ItemType>( ostream & outs, const List<ItemType>
& theList );

Why there is present <ItemType>after operator << ? What is the meaning of
it?
While defining the template function

template <typename ItemType>
ostream & operator<<( ostream & outs, const List<ItemType>& theList);

we don't include <ItemType>after operator<<
In that case, the template <typename ItemType>indicates that you are
declaring a function template. For the friend declaration, something is
needed to say that you are referring to a function template
specialization, not a non-template function, and the rules for friend
declarations say that the way to do this is with a template-id, like
'operator<< <ItemType>'.
Tom
 

Re:About friend template function

Thank you Tom.
There are controversial and incomplete descriptions of template in many C++
books.
Vladimir Grigoriev
"Tom Widmer" < XXXX@XXXXX.COM >wrote in message
Quote
Vladimir Grigoriev wrote:
>I don't only understand the syntax
>
>friend ostream & operator<< <ItemType>( ostream & outs, const
List<ItemType>
>& theList );
>
>Why there is present <ItemType>after operator << ? What is the meaning
of
>it?
>While defining the template function
>
>template <typename ItemType>
>ostream & operator<<( ostream & outs, const List<ItemType>&
theList);
>
>we don't include <ItemType>after operator<<

In that case, the template <typename ItemType>indicates that you are
declaring a function template. For the friend declaration, something is
needed to say that you are referring to a function template
specialization, not a non-template function, and the rules for friend
declarations say that the way to do this is with a template-id, like
'operator<< <ItemType>'.

Tom
 

Re:About friend template function

Vladimir Grigoriev < XXXX@XXXXX.COM >wrote:
Quote
Thank you Tom.
There are controversial and incomplete descriptions of template in many C++
books.
If you want to know it all, get "C++ Templates
The Complete Guide" by Vandervoorde & Josuttis.
Quote
Vladimir Grigoriev
[...]
Schobi
--
XXXX@XXXXX.COM is never read
I'm Schobi at suespammers dot org
"If you put a large switch in some cave somewhere, with a sign
on it saying 'End-of-the-World Switch. PLEASE DO NOT TOUCH',
the paint wouldn't even have time to dry."
Terry Pratchett