Sylvester said:
I'm a bit curious why this works (although both comeau and gcc seem to
allow it, however gcc complains with a link error (undefined reference to
`foo<int> bar<double>(foo<int>, foo<double>)').
foo<T> declares bar<T,U> as a friend, but not bar<U,T>. Therefore,
foo<double>::a shouldn't be accessible in the function bar<int, double>
(as that is not a bar<T,U> but a bar<U,T> to foo<T> with T=double and
U=int). Sadly enough, the standard isn't very clear about these specific
cases (or perhaps I'm misinterpreting something in 14.5.3).
It doesn't work. As a matter of fact, the code above introduces two versions
of bar. The friend version is what is called in main. Since the body of
that function never tries to access private members of foo<U>, the compiler
has no reason to complain. On the other hand, since that function is never
defined, you get a linker error. Let's define it to test this theory:
#include <iostream>
template<class T> class foo;
template<class T, class U>
foo<T> bar(foo<T>, foo<U>);
template<class T> class foo
{
int a;
template<class U> friend foo<T> bar(foo<T> a, foo<U> b) {
std::cout << "template friend called\n";
return ( a );
}
};
template<class T, class U>
foo<T> bar(foo<T> fT, foo<U> fU)
{
std::cout << "freestanding template called\n";
fT.a + fU.a;
return fT;
}
int main() {
foo<int> fint;
foo<double> fdouble;
bar(fint, fdouble);
}
This prints:
template friend called
However, as soon as the friend tries to access private members of foo<U>,
the code does not compile:
#include <iostream>
template<class T> class foo;
template<class T, class U>
foo<T> bar(foo<T>, foo<U>);
template<class T> class foo
{
int a;
template<class U> friend foo<T> bar(foo<T> a, foo<U> b) {
std::cout << "template friend called\n";
b.a;
return ( a );
}
};
template<class T, class U>
foo<T> bar(foo<T> fT, foo<U> fU)
{
std::cout << "freestanding template called\n";
fT.a + fU.a;
return fT;
}
int main() {
foo<int> fint;
foo<double> fdouble;
bar(fint, fdouble);
}
As for the original question: I have no idea how to do it without making the
function befriend of unrelated classes, too. But, what about:
#include <iostream>
template<class T> class foo;
template<class T, class U>
foo<T> bar(foo<T> fT, foo<U> fU);
template<class T> class foo
{
int a;
template< class A, class B >
friend
foo<A> bar ( foo<A>, foo<B> );
};
template<class T, class U>
foo<T> bar(foo<T> fT, foo<U> fU)
{
std::cout << "freestanding template called\n";
fT.a + fU.a;
return fT;
}
int main() {
foo<int> fint;
foo<double> fdouble;
bar(fint, fdouble);
}
Best
Kai-Uwe Bux