94

Let's say I'm creating a class for a binary tree, BT, and I have a class which describes an element of the tree, BE, something like

template<class T> class BE {
    T *data;
    BE *l, *r;
public:
...
    template<class U> friend class BT;
};

template<class T> class BT {
    BE<T> *root;
public:
...
private:
...
};

This appears to work; however I have questions about what's going on underneath.

I originally tried to declare the friend as

template<class T> friend class BT;

however it appears necessary to use U (or something other than T) here, why is this? Does it imply that any particular BT is friend to any particular BE class?

The IBM page on templates and friends has examples of different type of friend relationships for functions but not classes (and guessing a syntax hasn't converged on the solution yet). I would prefer to understand how to get the specifications correct for the type of friend relationship I wish to define.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
Michael Conlen
  • 1,959
  • 2
  • 17
  • 19

5 Answers5

133
template<class T> class BE{
  template<class T> friend class BT;
};

Is not allowed because template parameters cannot shadow each other. Nested templates must have different template parameter names.


template<typename T>
struct foo {
  template<typename U>
  friend class bar;
};

This means that bar is a friend of foo regardless of bar's template arguments. bar<char>, bar<int>, bar<float>, and any other bar would be friends of foo<char>.


template<typename T>
struct foo {
  friend class bar<T>;
};

This means that bar is a friend of foo when bar's template argument matches foo's. Only bar<char> would be a friend of foo<char>.


In your case, friend class bar<T>; should be sufficient.

Pubby
  • 51,882
  • 13
  • 139
  • 180
  • 2
    this construction in my code friend class BT throws an error for the friend line error: 'BT' is not a template even though it's declared later as template class BT { ... } – Michael Conlen Jan 23 '12 at 14:00
  • 3
    So the secret is that I needed to forward declare BT in order to use the friend class BT; line in the BE, but not for the template friend class BT;. Thanks for the help! – Michael Conlen Jan 23 '12 at 14:06
  • 26
    To be more specific: you have to forward declare `template class BT;` _before_ the definition of BE, and then use `friend class BT;` _inside_ the class BE. – Bartosz Milewski Nov 13 '13 at 02:40
10

In order to befriend another same-type struct:

#include <iostream>

template<typename T_>
struct Foo
{
    // Without this next line source.value_ later would be inaccessible.
    template<typename> friend struct Foo;

    Foo(T_ value) : value_(value) {}

    template <typename AltT>
    void display(AltT &&source) const
    {
        std::cout << "My value is " << value_ << " and my friend's value is " << source.value_ << ".\n";
    }

protected:
    T_ value_;
};

int main()
{
    Foo<int> foo1(5);
    Foo<std::string> foo2("banana");

    foo1.display(foo2);

    return 0;
}

With the output as follows:

My value is 5 and my friend's value is banana. 

In template<typename> friend struct Foo; you shouldn't write T after typename/class otherwise it will cause a template param shadowing error.

Robin R
  • 1,037
  • 10
  • 6
user6502769
  • 111
  • 1
  • 2
3

It's not necessary to name the parameters so you get fewer points of failure if refactoring:

     template <typename _KeyT, typename _ValueT> class hash_map_iterator{
       template <typename, typename, int> friend class hash_map;
       ...
0

The best way to make a template class a friend of a template class is the following:

#include <iostream>
using namespace std;

template<typename T>
class B;

template<typename T>
class A
{
   friend class B<T>;
private:
   int height;
public:
   A()//constructor
   A(T val) //overloaded constructor

};

template<typename T>
class B
{
private:
   ...
public:
   B()//constructor
   B(T val) //overloaded constructor
};
Ans naeem
  • 1
  • 4
  • This makes a particular specialization `B` a friend of specialization `A`. Templates themselves can't be friends, though the closest to what this could mean is to make all specializations of one template friends of all specializations of another template (then friend declaration has to be templated - see the accepted answer). – YurkoFlisk Oct 02 '22 at 17:04
-5

In my case this solution works correctly:

template <typename T>
class DerivedClass1 : public BaseClass1 {
  template<class T> friend class DerivedClass2;
private:
 int a;
};

template <typename T>
class DerivedClass2 : public BaseClass1 {
  void method() { this->i;}
};

I hope it will be helpful.

GutiMac
  • 2,402
  • 1
  • 20
  • 27
  • 7
    How is that solution supposed to work correctly when you're shadowing template parameters and otherwise not putting DerivedClass2's friend access to DerivedClass1 to use? – kornman00 Feb 01 '15 at 20:18