2

We have two class-templates: A and B, and a function-template f1(). Like this:

template< class T >
class A{};

template< class T >
class B
{
    friend class A<T>;          /* Expression 1 */
    friend void f1( B<T> &b );  /* Expression 2 */
};

template< class T >
void f1( B<T> &b ) {}

int main()
{
    A< int > a;
    B< int > b;

    f1( b );

    return 0;
}

problem 1: expression 1 make the specialization of A with argument T a friend of the specialization of B with argument T. But how to make every specialization of A all friends of specialization of B?

problem 2: how to define f1 outside the class definition? the code like this will generate an error:

undefined reference to `f1(B<int>&)'

problem 3: how to make all f1()s (who can receive all specialization of B as arguments) friends of every specialization of B?

Yishu Fang
  • 9,448
  • 21
  • 65
  • 102

2 Answers2

3

problem 1: use

template <typename U> friend class A; 

instead of

friend class A<T>;

problem 2: What expression 2 does is declaring friend a normal function taking a B, not the specialization of the function template. To declare friend the specialization for T, you need the friend clause to see a declaration of f1 and add <> to mark the f1 is a specialization and not an overloaded normal function, so

template< class T >
class B;
template< class T >
void f1( B<T> &b );
template< class T >
class B
{
    friend void f1<>( B<T> &b );
};

template< class T >
void f1( B<T> &b ) {}

problem 3 solution is a mix of the two:

class B;
template< class T >
void f1( B<T> &b );
template< class T >
class B
{
    template <typename U> friend void f1( B<U> &b );
};
AProgrammer
  • 51,233
  • 8
  • 91
  • 143
2

Problem 1:

Do you really want to do it? Do you want A<int> to access B<float>? Usually you don't, but if you really want:

template <typename U>
friend class A;

Problem 2:

The problem in 2 is that you are not making the instantiation of the f1 template a friend, but rather you are trying to make a non-templated free function f1 that takes a B<int> your friend. The correct syntax to befriend a particular instantiation is cumbersome:

template <typename T> class B;
template <typename T> void f( B<T>& );
template <typename T>
class B {
   friend void f<T>( B<T>& );
};

Problem 3:

To make all specializations of f1 a friend (again, do you really want this?), you can do the same approach as for the class template:

template <typename U>
friend void f1( B<U>& );

More on all those here

Community
  • 1
  • 1
David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • What's the difference between `template friend class A` and `template friend class A`? I don't understand. @David Rodriguez – Yishu Fang Mar 13 '12 at 15:53
  • @UniMouS: If you mean the edit, fixing a typo (I think). This is one of those things that I hardly ever write, and the syntax is not that straight forward, I reviewed the other answer I wrote quite some time ago that I had *verified* with a compiler and made the syntax consistent. – David Rodríguez - dribeas Mar 13 '12 at 15:56
  • Oh, thank you for your answer, I am a beginner in C++ and I don't quite understand that syntax. @David Rodriguez – Yishu Fang Mar 13 '12 at 16:11
  • @UniMouS: In this particular case, the syntax is complex enough and not really well understood in general that even experienced programmers don't get it right in the first try. – David Rodríguez - dribeas Mar 13 '12 at 16:46