Confused about friends in template class

S

StephQ

According to:
http://www.parashift.com/c++-faq-lite/templates.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<A> friend 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
 
F

Fei Liu

StephQ said:
According to:
http://www.parashift.com/c++-faq-lite/templates.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...
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?
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<A> friend 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.
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.
 
S

StephQ

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 :)
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?
I couldn't think of any reason to avoid using it.

Perfect.

Thank you for you reply.

Cheers
StephQ
 
F

Fei Liu

StephQ said:
Here i just wanted to check if I understood the explanation correctly.
It seemes this is the case :)


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 T> for 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<T> definition 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<T> and func<U> are 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<int> fi;
Foo<float> ff;
ff.func(fi);

A common use is to write copy constructors this way to convert between
different template instantation of types.
 
S

StephQ

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

};

What's the point of declaring template <typename T> for 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<T> definition 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<T> and func<U> are 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<int> fi;
Foo<float> ff;
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
 

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

Forum statistics

Threads
473,995
Messages
2,570,230
Members
46,818
Latest member
Brigette36

Latest Threads

Top