g++ 4.5 can't find a friend function

2020-04-12 09:18发布

问题:

G'day!

I have a question around the use of friend in C++. Consider the following piece of code:

#include <ostream>

struct F {
};

struct N {
  friend std::ostream& operator<< (std::ostream&, const N&);
  friend std::ostream& operator<< (std::ostream&, const F&);    
};

void foo(std::ostream &out) {
  F bar;
  out << bar;
}

My understanding always was, that friend is similar to static with the additional property that the friend function has access to the private part of the class. Under that assumption, the code should compile, since there is an operator<< that takes an ostream& and a (const) F&.

It appears that g++ 4.0 shares my thoughts on this, as it accepts that code. The much newer g++ 4.5(.2) however, rejects the code with the message:

ns.cc: In function 'void foo(std::ostream&)':
ns.cc:14:10: error: no match for 'operator<<' in 'out << bar'

is g++ 4.5 wrong or am I (and g++ 4.0) wrong?

(The solution to move the friend declaration into the F class doesn't help, as the operator<< will need access to the private part of N.)

Regards, Stefan

回答1:

You have to declare the operators outside the struct as well. Same error is reported by gcc 4.4.

#include <ostream>

struct F {
};

struct N {
  friend std::ostream& operator<< (std::ostream&, const N&);
  friend std::ostream& operator<< (std::ostream&, const F&);    
};

std::ostream& operator<< (std::ostream&, const N&);
std::ostream& operator<< (std::ostream&, const F&);    

void foo(std::ostream &out) {
  F bar;
  out << bar;
}


回答2:

The problem is that a friend declaration doesn't provide a global function declaration, unless you provide an inline implementation.

struct N {
   friend void func1() { }
   friend void func2();
   friend void func3();
};

void func3();

func1(); /* OK */
func2(); /* not OK */
func3(); /* OK */


回答3:

I've been trudging through the standard (FCD, n3242) since I saw the question

In [class.friend] one can read:

6) A function can be defined in a friend declaration of a class if and only if the class is a non-local class (9.8), the function name is unqualified, and the function has namespace scope.

7) Such a function is implicitly inline. A friend function defined in a class is in the (lexical) scope of the class in which it is defined. A friend function defined outside the class is not (3.4.1).

9) A name nominated by a friend declaration shall be accessible in the scope of the class containing the friend declaration.

So, what happens here ?

struct F {
};

struct N {
  friend std::ostream& operator<< (std::ostream&, const F&);    
};

The friend declaration nominates this overload of operator<< to be a friend of N. However this overload has not been declared in a lexical scope (either namespace or class). Also, 7 does not apply because it is not defined within N either.

Therefore, when looking up the overloads of operator<< that can apply in:

void foo(std::ostream &out) {
  F bar;
  out << bar;
}

There is no valid overload (actually, it could be there is no overload at all).

You have two solutions:

  • use 7: define the function inline following the friend declaration.
  • use 9: declare the function in the namespace too

Because of 4 though:

4) A function first declared in a friend declaration has external linkage (3.5). Otherwise, the function retains its previous linkage (7.1.1).

I would recommend declaring it prior to the friend declaration to control its linkage, but it will rarely matters.



标签: c++ g++ friend