Reputation: 9404
Let I have such class Foo
and its friend function ::f
:
template <typename T>
class Foo {
public:
template <typename U>
friend inline void f(Foo<T>, Foo<U>) {}
};
Then I call it like this f(Foo<double>(), Foo<int>())
,
friend of who will be ::f
?
Only Foo<double>
or it will
be friend of Foo<int>
also, I mean ::f
become friend for Foo<T>
for any T
at the time of declaration, or at the time of usage compiler generate ::f
for T=double
and find out that it is friend of Foo<double>
and not friend of Foo<int>
?
And if I declare ::f
like this:
template <typename T>
class Foo {
public:
template <typename U1, typename U2>
friend inline void f(Foo<U1>, Foo<U2>) {}
};
Again friend of who become ::f
after call f(Foo<double>(), Foo<int>());
Note: the second variant compiled only by clang, not gcc.
Note it would be great to see answers with reference to standard.
Upvotes: 2
Views: 351
Reputation: 52611
You don't have a single function template - you have an unbounded family of them. With each instantiation Foo<X>
, a new function template is defined,
template <typename U>
void f(Foo<X>, Foo<U>) {}
All instantiations of this template are friends of Foo<X>
(but not of any Foo<U>
for U != X
).
Thus, when you write f(Foo<double>(), Foo<int>())
, Foo<double>
and Foo<int>
are instantiated, and with them, two overloads of f
are defined:
template <typename U>
void f(Foo<double>, Foo<U>) {}
template <typename U>
void f(Foo<int>, Foo<U>) {}
Overload resolution selects the first one for the call (the second is not viable), which is instantiated for U==int
. This instantiation, f<int>(Foo<double>, Foo<int>)
, is a friend of Foo<double>
but not Foo<int>
.
In your second example, I believe gcc is right in rejecting the code, and clang is wrong in accepting it (for what it's worth, MSVC agrees with gcc). Every instantiation of Foo<X>
introduces a definition of the same template into the enclosing scope:
template <typename U1, typename U2>
void f(Foo<U1>, Foo<U2>) {}
When a translation unit performs two instantiaions of Foo
, it ends up with two identical definitions of f
, hence the error.
Upvotes: 2