Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C++ > Template friend in templat class

Reply
Thread Tools

Template friend in templat class

 
 
Fred Zwarts \(KVI\)
Guest
Posts: n/a
 
      07-20-2012
I have a template class:

template <typename Base_t> class Rational_t {

// Definition of private and public members left out.
// Probably not relevant.

};

I want an output operator << for this class for different output streams.
I am not sure that I completely understand the hierarchy of the i/o stream
classes, but I have the impression that the base class in which the operator
<< is defined is a template class. (It would be much easier if the first
class in which the << operator is defined, were a non-template class.) So, I
need at least two template parameters for my << operator. Therefore, in the
same header file I had:

template <typename Base_t, typename ostream_t>
ostream_t & operator<<
(ostream_t & out, const Rational_t<Base_t> & Rat) {

// Implementation left out.
// Probably not relevant.

}

This works.

Now, I want to change the implementation of the << operator a bit, for which
it needs access to some private members of the Rational_t class. Therefore,
I want to make the << operator a friend of the class. This requires a few
forward declarations at the start of the file.

template <typename Base_t> class Rational_t;

template <typename Base_t, typename ostream_t>
ostream_t & operator<<
(ostream_t & out, const Rational_t<Base_t> & Rat);

This also still works, as long as the implementation of the << operator does
not access the private members of Rational_t.

I have tried several ways to write the friend declaration, but non of them
works.
I think the last one I tried was:

template <typename Base_t> class Rational_t {

template <typename ostream_t>
friend ostream_t& operator<<
(ostream_t& out, const Rational_t & Rat);

// Definition of private and public members left out.
// Probably not relevant.

};

When I use g++ under Linux
(g++ (SUSE Linux) 4.3.4 [gcc-4_3-branch revision 152973]),
I see a lot of messages like (One long line wrapped by me.):

TestRational.cpp.text+0xa93): undefined reference to
`std::basic_ostream<char, std::char_traits<char> >&
Rational:perator<<
<std::basic_ostream<char, std::char_traits<char> > >
(std::basic_ostream<char, std::char_traits<char> >&,
Rational::Rational_t<int> const&)'

It seems that the compiler has no problem with the code, but the linker has.
Usually this indicates that the friend declaration is interpreted as a
forward declaration, for which no implementation is found. So apparently
something is wrong with the friend declaration. But I don't see how I can
make it work.
Any suggestion?

 
Reply With Quote
 
 
 
 
Fred Zwarts \(KVI\)
Guest
Posts: n/a
 
      07-20-2012
"Fred Zwarts (KVI)" wrote in message news:jubolr$kn1$(E-Mail Removed)...
>
>I have a template class:
>
>template <typename Base_t> class Rational_t {
>
>// Definition of private and public members left out.
>// Probably not relevant.
>
>};
>
>I want an output operator << for this class for different output streams.
>I am not sure that I completely understand the hierarchy of the i/o stream
>classes, but I have the impression that the base class in which the
>operator << is defined is a template class. (It would be much easier if the
>first class in which the << operator is defined, were a non-template
>class.) So, I need at least two template parameters for my << operator.
>Therefore, in the same header file I had:
>
>template <typename Base_t, typename ostream_t>
>ostream_t & operator<<
> (ostream_t & out, const Rational_t<Base_t> & Rat) {
>
>// Implementation left out.
>// Probably not relevant.
>
>}
>
>This works.
>
>Now, I want to change the implementation of the << operator a bit, for
>which it needs access to some private members of the Rational_t class.
>Therefore, I want to make the << operator a friend of the class. This
>requires a few forward declarations at the start of the file.
>
>template <typename Base_t> class Rational_t;
>
>template <typename Base_t, typename ostream_t>
>ostream_t & operator<<
> (ostream_t & out, const Rational_t<Base_t> & Rat);
>
>This also still works, as long as the implementation of the << operator
>does not access the private members of Rational_t.
>
>I have tried several ways to write the friend declaration, but non of them
>works.
>I think the last one I tried was:
>
>template <typename Base_t> class Rational_t {
>
>template <typename ostream_t>
> friend ostream_t& operator<<
> (ostream_t& out, const Rational_t & Rat);
>
>// Definition of private and public members left out.
>// Probably not relevant.
>
>};
>
>When I use g++ under Linux
>(g++ (SUSE Linux) 4.3.4 [gcc-4_3-branch revision 152973]),
>I see a lot of messages like (One long line wrapped by me.):
>
>TestRational.cpp.text+0xa93): undefined reference to
>`std::basic_ostream<char, std::char_traits<char> >&
>Rational:perator<<
><std::basic_ostream<char, std::char_traits<char> > >
>(std::basic_ostream<char, std::char_traits<char> >&,
>Rational::Rational_t<int> const&)'
>
>It seems that the compiler has no problem with the code, but the linker
>has.
>Usually this indicates that the friend declaration is interpreted as a
>forward declaration, for which no implementation is found. So apparently
>something is wrong with the friend declaration. But I don't see how I can
>make it work.
>Any suggestion?


I forgot to mention that both the class and the << operator are in the
namespace Rational,
which is seen in the error message.

 
Reply With Quote
 
 
 
 
Victor Bazarov
Guest
Posts: n/a
 
      07-20-2012
On 7/20/2012 10:06 AM, Fred Zwarts (KVI) wrote:
> I have a template class:
>
> [..blah..]
> Any suggestion?
>


Here is a suggestion: post the *simplest possible* code in such a way
that we can copy it from your message and paste it into our text editor
and hit the "build" button. The code you post should produce the exact
message you quote when compiled with the exact compiler you mention.
See FAQ 5.8. If I have to gather fragments of code from your post and
then massage it into compilation by adding some other parts like the
**** you decided wasn't important, etc., it's *too much work* for *no
pay*. Keep that in mind when asking for help, please.

V
--
I do not respond to top-posted replies, please don't ask


 
Reply With Quote
 
Fred Zwarts \(KVI\)
Guest
Posts: n/a
 
      07-20-2012
"Victor Bazarov" wrote in message news:jubpl4$5jk$(E-Mail Removed)...
>
>On 7/20/2012 10:06 AM, Fred Zwarts (KVI) wrote:
>> I have a template class:
>>
>> [..blah..]
>> Any suggestion?
>>

>
>Here is a suggestion: post the *simplest possible* code in such a way that
>we can copy it from your message and paste it into our text editor and hit
>the "build" button. The code you post should produce the exact message you
>quote when compiled with the exact compiler you mention. See FAQ 5.8. If I
>have to gather fragments of code from your post and then massage it into
>compilation by adding some other parts like the **** you decided wasn't
>important, etc., it's *too much work* for *no pay*. Keep that in mind when
>asking for help, please.


Sorry, that I formulated my question to generally. It was not my purpose
that you should try to get the same error message from the compiler as I
did. I only wanted to know how to make the correct friend declaration. As I
understand it, a friend declaration does not depend on the exact
implementation of the class and the operator. If you don't now how to make
such a friend declaration, I didn't want you to experiment with the compiler
until the error disappears. I know that it is too much work.

 
Reply With Quote
 
Victor Bazarov
Guest
Posts: n/a
 
      07-20-2012
On 7/20/2012 11:22 AM, Fred Zwarts (KVI) wrote:
> "Victor Bazarov" wrote in message news:jubpl4$5jk$(E-Mail Removed)...
>>
>> On 7/20/2012 10:06 AM, Fred Zwarts (KVI) wrote:
>>> I have a template class:
>>>
>>> [..blah..]
>>> Any suggestion?
>>>

>>
>> Here is a suggestion: post the *simplest possible* code in such a way
>> that we can copy it from your message and paste it into our text
>> editor and hit the "build" button. The code you post should produce
>> the exact message you quote when compiled with the exact compiler you
>> mention. See FAQ 5.8. If I have to gather fragments of code from your
>> post and then massage it into compilation by adding some other parts
>> like the **** you decided wasn't important, etc., it's *too much work*
>> for *no pay*. Keep that in mind when asking for help, please.

>
> Sorry, that I formulated my question to generally. It was not my purpose
> that you should try to get the same error message from the compiler as I
> did. I only wanted to know how to make the correct friend declaration.
> As I understand it, a friend declaration does not depend on the exact
> implementation of the class and the operator. If you don't now how to
> make such a friend declaration, I didn't want you to experiment with the
> compiler until the error disappears. I know that it is too much work.


<shrug> Whatever. Let's hope you figure it out by yourself (better) or
somebody smarter and/or not too busy will do your figuring out for you.
Good luck!

V
--
I do not respond to top-posted replies, please don't ask


 
Reply With Quote
 
Luca Risolia
Guest
Posts: n/a
 
      07-20-2012
On 20/07/2012 16:06, Fred Zwarts (KVI) wrote:
> When I use g++ under Linux
> (g++ (SUSE Linux) 4.3.4 [gcc-4_3-branch revision 152973]),
> I see a lot of messages like (One long line wrapped by me.):
>
> TestRational.cpp.text+0xa93): undefined reference to
> `std::basic_ostream<char, std::char_traits<char> >&
> Rational:perator<<
> <std::basic_ostream<char, std::char_traits<char> > >
> (std::basic_ostream<char, std::char_traits<char> >&,
> Rational::Rational_t<int> const&)'
>
> It seems that the compiler has no problem with the code, but the linker
> has.
> Usually this indicates that the friend declaration is interpreted as a
> forward declaration, for which no implementation is found. So apparently
> something is wrong with the friend declaration. But I don't see how I
> can make it work.
> Any suggestion?


It seems your ostream_t is just a std::basic_ostream<>, so use the
latter directly if you can:

template <typename Base_t>
class Rational_t {
template<class Ch, class Tr, class Base_t_>
friend std::basic_ostream<Ch, Tr>&
operator<<(std::basic_ostream<Ch, Tr>&, const Rational_t<Base_t_>&);
};

template<class Ch, class Tr, class Base_t>
std::basic_ostream<Ch, Tr>& operator<<(std::basic_ostream<Ch, Tr>& out,
const Rational_t<Base_t>& rat) {
}


 
Reply With Quote
 
Nobody
Guest
Posts: n/a
 
      07-21-2012
On Fri, 20 Jul 2012 16:06:51 +0200, Fred Zwarts (KVI) wrote:

> template <typename Base_t> class Rational_t {
>
> template <typename ostream_t>
> friend ostream_t& operator<<
> (ostream_t& out, const Rational_t & Rat);


> When I use g++ under Linux
> (g++ (SUSE Linux) 4.3.4 [gcc-4_3-branch revision 152973]),
> I see a lot of messages like (One long line wrapped by me.):
>
> TestRational.cpp.text+0xa93): undefined reference to
> `std::basic_ostream<char, std::char_traits<char> >&
> Rational:perator<<
> <std::basic_ostream<char, std::char_traits<char> > >
> (std::basic_ostream<char, std::char_traits<char> >&,
> Rational::Rational_t<int> const&)'
>
> It seems that the compiler has no problem with the code, but the linker has.


AFAICT, the friend declaration causes the compiler to assume the existence
of multiple operator<< function templates, one for each instance of the
rational template, each with the ostream type as the sole template
parameter, i.e.

template <typename ostream_t>
ostream_t& operator<<(ostream_t& out, const Rational_t<int> & Rat);

template <typename ostream_t>
ostream_t& operator<<(ostream_t& out, const Rational_t<long> & Rat);

....

rather than a single function template with both the ostream and rational
types as parameters, i.e.

template <typename ostream_t, typename base_t>
ostream_t& operator<<(ostream_t& out, const Rational_t<base_t> & Rat);

Because the template parameters are part of the mangled symbol name,
calling the former while only defining the latter will result in an
undefined symbol error.

This works:

template <typename ostream_t, typename base_t>
friend ostream_t& operator<<(ostream_t& out, const Rational_t<base_t>& Rat);

It's more general than your attempt, i.e. all such operator<< functions
are friends of all Rational_t instances rather than just the instance used
in the second argument. However, I don't know whether it's possible to
friend a partial function specialisation (I know that you can't *define* a
partial function specialisation).

 
Reply With Quote
 
Gerhard Fiedler
Guest
Posts: n/a
 
      07-21-2012
Fred Zwarts (KVI) wrote:

> "Victor Bazarov" wrote in message news:jubpl4$5jk$(E-Mail Removed)...
>> Here is a suggestion: post the *simplest possible* code in such a way
>> that we can copy it from your message and paste it into our text
>> editor and hit the "build" button. The code you post should produce
>> the exact message you quote when compiled with the exact compiler
>> you mention. See FAQ 5.8. If I have to gather fragments of code
>> from your post and then massage it into compilation by adding some
>> other parts like the **** you decided wasn't important, etc., it's
>> *too much work* for *no pay*. Keep that in mind when asking for
>> help, please.

>
> Sorry, that I formulated my question to generally. It was not my
> purpose that you should try to get the same error message from the
> compiler as I did. I only wanted to know how to make the correct
> friend declaration. As I understand it, a friend declaration does not
> depend on the exact implementation of the class and the operator. If
> you don't now how to make such a friend declaration, I didn't want
> you to experiment with the compiler until the error disappears. I
> know that it is too much work.


Consider also that reducing the problem to the simplest possible code
that shows the problem behavior is most of the time an interesting
learning exercise. It challenges your understanding, makes you think
differently than by looking at the problem in the context of your
specific application, and often you'll find the answer yourself while
doing this.

If you still don't find an answer, you can easily do what Victor asked
you to do, because you have this complete (and often rather simple) code
example right in front of you -- and most of the time with some
additional (and specific) information about things you tried that didn't
work, specific (and reproducible) error messages etc.

Gerhard
 
Reply With Quote
 
Fred Zwarts \(KVI\)
Guest
Posts: n/a
 
      07-23-2012
"Nobody" wrote in message
news(E-Mail Removed)...
>
>On Fri, 20 Jul 2012 16:06:51 +0200, Fred Zwarts (KVI) wrote:
>
>> template <typename Base_t> class Rational_t {
>>
>> template <typename ostream_t>
>> friend ostream_t& operator<<
>> (ostream_t& out, const Rational_t & Rat);

>
>> When I use g++ under Linux
>> (g++ (SUSE Linux) 4.3.4 [gcc-4_3-branch revision 152973]),
>> I see a lot of messages like (One long line wrapped by me.):
>>
>> TestRational.cpp.text+0xa93): undefined reference to
>> `std::basic_ostream<char, std::char_traits<char> >&
>> Rational:perator<<
>> <std::basic_ostream<char, std::char_traits<char> > >
>> (std::basic_ostream<char, std::char_traits<char> >&,
>> Rational::Rational_t<int> const&)'
>>
>> It seems that the compiler has no problem with the code, but the linker
>> has.

>
>AFAICT, the friend declaration causes the compiler to assume the existence
>of multiple operator<< function templates, one for each instance of the
>rational template, each with the ostream type as the sole template
>parameter, i.e.
>
> template <typename ostream_t>
> ostream_t& operator<<(ostream_t& out, const Rational_t<int> & Rat);
>
> template <typename ostream_t>
> ostream_t& operator<<(ostream_t& out, const Rational_t<long> & Rat);
>
>...


I had tried also the following friend declaration:

template <typename ostream_t>
ostream_t& operator<<(ostream_t& out, const Rational_t<Base_t> & Rat);

but it resulted in the same erro message.

>
>rather than a single function template with both the ostream and rational
>types as parameters, i.e.
>
> template <typename ostream_t, typename base_t>
> ostream_t& operator<<(ostream_t& out, const Rational_t<base_t> & Rat);
>
>Because the template parameters are part of the mangled symbol name,
>calling the former while only defining the latter will result in an
>undefined symbol error.
>
>This works:
>
> template <typename ostream_t, typename base_t>
> friend ostream_t& operator<<(ostream_t& out, const Rational_t<base_t>&
> Rat);
>
>It's more general than your attempt, i.e. all such operator<< functions
>are friends of all Rational_t instances rather than just the instance used
>in the second argument. However, I don't know whether it's possible to
>friend a partial function specialisation (I know that you can't *define* a
>partial function specialisation).


Thanks. That is the solution. (Although as you noticed a bit too general,
but in this case it does not matter.)

Probably this all means that it is not possible to friend a partial function
specialisation. I don't have the C++ standard here, so I can't check.

 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Declaring a template class with two template params a friend in anon-template class A L C++ 1 08-25-2010 07:25 AM
Problem using a FormView with an HTML table in Edit/Insert templat =?Utf-8?B?TG9yZW56aW5v?= ASP .Net 7 04-14-2006 06:50 AM
Problem with defining template friend function of a template class. PengYu.UT@gmail.com C++ 2 11-09-2005 08:27 PM
A parameterized class (i.e. template class / class template) is not a class? christopher diggins C++ 16 05-04-2005 12:26 AM
using friend function template in class template Yueh-Wei Hu C++ 0 05-23-2004 11:36 AM



Advertisments