3

I am trying to declare a function as friend to a class template with a protected member. Below is a minimal example.

template<int N> class myClass{
public:
    friend void f(const myClass& c);
protected:
    int a;
};

If I now define the function as

template<int N> void f(const myClass<N>& c){
    std::cout << c.a;
};

Then it works.

However if I use template specialisation

template<int N> void f(const myClass<N>& c);
template<> void f<1>(const myClass<1>& c){
    std::cout << c.a;
};

It does not recognise f as a friend anymore and complains that a is a protected member.

Why is that happening? What am I doing wrong?

marco
  • 167
  • 6
  • 2
    when you say "it works" it does not actually work https://godbolt.org/z/93E6q1vr9. The error is the same. Please do include the error message in the quesiton. It should be rather clear about whats wrong – 463035818_is_not_an_ai Nov 07 '22 at 10:51
  • 1
    Because `friend void f(const myClass& c);` is a **nontemplate** friend declaration. That is, it befriends a nontemplate free function. – Jason Nov 07 '22 at 10:53
  • 1
    Neither of these will work once you actually try to use the function. The compiler will probably also warn you why. You are not declaring the same overload as `friend` as you are defining later. Make sure the declarations match: `template friend void f(const myClass&);` – user17732522 Nov 07 '22 at 10:53
  • Indeed you are right. I was not getting any warning in the first case, but I did not actually try to run the function. When I did neither worked. Thanks! – marco Nov 07 '22 at 10:59

1 Answers1

5

The problem is that the friend declaration friend void f(const myClass& c); is a nontemplate friend declaration. That is, you're actually befriending a nontemplae free function. This is exactly what the warning tells you:

 warning: friend declaration 'void f(const myClass<N>&)' declares a non-template function [-Wnon-template-friend]
   12 |     friend void f(const myClass& c);

To solve this you need to add a separate parameter clause for the friend declaration as shown below:

template<int N> class myClass{
public:
    template<int M>        //added this parameter clause
    friend void f(const myClass<M>& c);
protected:
    int a;
};

Working demo

Jason
  • 36,170
  • 5
  • 26
  • 60