Connecting Tech Pros Worldwide Forums | Help | Site Map

Confused about friends in template class

StephQ
Guest
 
Posts: n/a
#1: May 16 '07
According to:
http://www.parashift.com/c++-faq-lit....html#faq-35.4
, if my understanding is correct, in

template<typename T>
class Foo {
friend void func (const Foo<T>& foo);
};

template<typename T>
void func (const Foo<T>& foo) { ... }

func is seen as a non-template function at class instantation time,
and the func function template is never actually instantieted, so the
linker error (the compiler is searching the ordinary one).

The proposed solution is via forward declaration, but (in VC 8) this
works:

template<typename T>
class Foo {

template<typename T>
friend void func (const Foo<T>& foo);
};

template<typename T>
void func (const Foo<T>& foo) { ... }


However gcc complains about the fact that T (of func) shadows T (of
Foo), but the following works:

template<typename T>
class Foo {

template<typename U>
friend void func (const Foo<U>& foo);
};

template<typename T// Or U, indifferent right?
friend void func (const Foo<T>& foo);

According to a book of mine (maybe outdated, 2002) it seems that the
difference between this last option and the one proposed in the guide
is that here func can be a friend of classes with different templates,
like:
func<Afriend of Foo<B>
while in the solution proposed in the guide this can not happend.

My intuition (probably wrong) is than that the "invalid VC syntax"
really means to the VC compiler the situation illustrated in the guide
via forward declaration, but this syntax is illegal according to the
standard.
Too bad, I liked this more concise solution :)

Anyway, if my understanding was correct, there are reasons to avoid
using always the last option, where the function is also a friend of
instantation of the class with different parameters?

Cheers
StephQ


Fei Liu
Guest
 
Posts: n/a
#2: May 16 '07

re: Confused about friends in template class


StephQ wrote:
Quote:
According to:
http://www.parashift.com/c++-faq-lit....html#faq-35.4
, if my understanding is correct, in
>
template<typename T>
class Foo {
friend void func (const Foo<T>& foo);
};
You declared a non-template function func here...
Quote:
>
template<typename T>
void func (const Foo<T>& foo) { ... }
>
func is seen as a non-template function at class instantation time,
and the func function template is never actually instantieted, so the
linker error (the compiler is searching the ordinary one).
And the compiler couldn't find a non-template function func to
instantiate Foo...What's confusing you?
Quote:
>
The proposed solution is via forward declaration, but (in VC 8) this
works:
>
template<typename T>
class Foo {
>
template<typename T>
friend void func (const Foo<T>& foo);
};
>
template<typename T>
void func (const Foo<T>& foo) { ... }
>
>
However gcc complains about the fact that T (of func) shadows T (of
Foo), but the following works:
>
template<typename T>
class Foo {
>
template<typename U>
friend void func (const Foo<U>& foo);
};
>
template<typename T// Or U, indifferent right?
friend void func (const Foo<T>& foo);
>
According to a book of mine (maybe outdated, 2002) it seems that the
difference between this last option and the one proposed in the guide
is that here func can be a friend of classes with different templates,
like:
func<Afriend of Foo<B>
while in the solution proposed in the guide this can not happend.
>
My intuition (probably wrong) is than that the "invalid VC syntax"
really means to the VC compiler the situation illustrated in the guide
via forward declaration, but this syntax is illegal according to the
standard.
Too bad, I liked this more concise solution :)
It's concise but it's illogical and wrong, even though it may appear
convenient.
Quote:
>
Anyway, if my understanding was correct, there are reasons to avoid
using always the last option, where the function is also a friend of
instantation of the class with different parameters?
I couldn't think of any reason to avoid using it.
Quote:
>
Cheers
StephQ
>
StephQ
Guest
 
Posts: n/a
#3: May 17 '07

re: Confused about friends in template class


And the compiler couldn't find a non-template function func to
Quote:
instantiate Foo...What's confusing you?
Here i just wanted to check if I understood the explanation correctly.
It seemes this is the case :)
Quote:
It's concise but it's illogical and wrong, even though it may appear
convenient.
Could expand the explanation a little more?
Is it wrong according to the standard? There is a particular reason
for that?
Quote:
I couldn't think of any reason to avoid using it.
Perfect.

Thank you for you reply.

Cheers
StephQ



Fei Liu
Guest
 
Posts: n/a
#4: May 17 '07

re: Confused about friends in template class


StephQ wrote:
Quote:
Quote:
>And the compiler couldn't find a non-template function func to
>instantiate Foo...What's confusing you?
>
Here i just wanted to check if I understood the explanation correctly.
It seemes this is the case :)
>
Quote:
>It's concise but it's illogical and wrong, even though it may appear
>convenient.
>
Could expand the explanation a little more?
Is it wrong according to the standard? There is a particular reason
for that?
>
template<typename T>
class Foo {
public:
template<typename T>
friend void func (const Foo<T>& foo);
};

What's the point of declaring template <typename Tfor func? It gets
the template parameter by the function signature, i.e the argument. func
will be instantiated based on Foo's template paramter T. This is why you
are getting complaints from gcc. No need for standard to understand that
this is an dubious declaration. Once you remove the function template
declaration, you create a binding that for any instance of Foo<T>, there
must be a func<Tdefinition that completes it unless it's never used
anywhere (but that's not the point here).

It's an completely different story when you say:
template<typename T>
class Foo {
public:
template<typename U>
friend void func (const Foo<U>& foo);
};

Here you U and T are orthogonal and Foo<Tand func<Uare too. You
don't create any binding between these two definitions (sort of, when
you invoke func, its template argument type is determined by its
argument). This is a common way to get different template instantiations
to work together. Not in this particular example, but for this one:
template <typename T>
class Foo {
public:
template<typename U>
Foo<T>& func (const Foo<U>& foo);
};

Foo<intfi;
Foo<floatff;
ff.func(fi);

A common use is to write copy constructors this way to convert between
different template instantation of types.
Quote:
Quote:
>I couldn't think of any reason to avoid using it.
>
Perfect.
>
Thank you for you reply.
>
Cheers
StephQ
>
>
>
StephQ
Guest
 
Posts: n/a
#5: May 17 '07

re: Confused about friends in template class


On May 17, 11:26 pm, Fei Liu <fei...@aepnetworks.comwrote:
Quote:
StephQ wrote:
Quote:
Quote:
And the compiler couldn't find a non-template function func to
instantiate Foo...What's confusing you?
>
Quote:
Here i just wanted to check if I understood the explanation correctly.
It seemes this is the case :)
>
Quote:
Quote:
It's concise but it's illogical and wrong, even though it may appear
convenient.
>
Quote:
Could expand the explanation a little more?
Is it wrong according to the standard? There is a particular reason
for that?
>
template<typename T>
class Foo {
public:
template<typename T>
friend void func (const Foo<T>& foo);
>
};
>
What's the point of declaring template <typename Tfor func? It gets
the template parameter by the function signature, i.e the argument. func
will be instantiated based on Foo's template paramter T. This is why you
are getting complaints from gcc. No need for standard to understand that
this is an dubious declaration. Once you remove the function template
declaration, you create a binding that for any instance of Foo<T>, there
must be a func<Tdefinition that completes it unless it's never used
anywhere (but that's not the point here).
>
It's an completely different story when you say:
template<typename T>
class Foo {
public:
template<typename U>
friend void func (const Foo<U>& foo);
>
};
>
Here you U and T are orthogonal and Foo<Tand func<Uare too. You
don't create any binding between these two definitions (sort of, when
you invoke func, its template argument type is determined by its
argument). This is a common way to get different template instantiations
to work together. Not in this particular example, but for this one:
template <typename T>
class Foo {
public:
template<typename U>
Foo<T>& func (const Foo<U>& foo);
>
};
>
Foo<intfi;
Foo<floatff;
ff.func(fi);
>
A common use is to write copy constructors this way to convert between
different template instantation of types.
Thank you for your explanation.
Now the problem is much clearer to me.

Best Regards
StephQ


Closed Thread