Why is this friend method not found as expected? - c++

When I have a small piece of code like this:
#include <iostream>
class A {
public:
friend inline std::ostream& operator<<(std::ostream& os, const A&);
};
inline std::ostream& operator<<(std::ostream& os, const A&) {
os << "Called\n";
return os;
}
class B {
public:
operator A() { return A(); }
};
int main()
{
A a;
std::cout << a;
B b;
std::cout << b;
}
the operator<< is called twice for both a and b, because b has an implicit user conversion operator for type A. But I was surprised when I modified the code to this:
#include <iostream>
class A {
public:
friend std::ostream& operator<<(std::ostream& os, const A&) {
os << "Called\n";
return os;
}
};
class B {
public:
operator A() { return A(); }
};
int main()
{
A a;
std::cout << a;
B b;
std::cout << b;
}
As you see, I have just transferred the definition inside the class rather than using a free function and marking it as a friend of the class. But this code gives an error which says no suitable function for operator<< is found for b.
Why does this problem happen?

It comes down to how C++ generates candidate functions when performing overload resolution. It's trying to find candidates for operator<<(std::cout, b). This means it performs unqualified name lookup which includes performing argument-dependent lookup (ADL). Let's take a look at how that works.
For the first code snippet, unqualified name lookup finds the declaration when it looks in the enclosing scope of the calling code, without needing to perform ADL. It sees inline std::ostream& operator<<(std::ostream& os, const A&) as a candidate, and then is able to apply the user-defined conversion to b to see that it's a valid function to use for overload resolution. All well and good.
For the second code snippet, though, we don't have a declaration of operator<< at file scope. The declaration and definition are entirely within the definition of the class A. That still might let us find it as a candidate function for std::cout << b, but it'll have to be through ADL. Let's check to see if it's actually visible through that:
Otherwise, for every argument in a function call expression its type
is examined to determine the associated set of namespaces and classes
that it will add to the lookup.
...
For arguments of class type (including union),
the set consists of
a) The class itself
b) All of its direct and indirect base classes
c) If the class is a member of another class, the class of which it is a member
d) The innermost enclosing namespaces of the classes added to the set
At any stage, would we look inside the definition of A when performing ADL with arguments std::cout and b? None of a), b), and c) apply to A because A isn't B, A isn't a base class of B, and A doesn't contain B as a member. Crucially, "any class to which the class is implicitly convertible" isn't used to generate candidates through ADL.
So ultimately in the second code snippet, the name lookup never sees the declaration of std::ostream& operator<<(std::ostream& os, const A&) and never realizes that it can apply a user-defined conversion to apply it with the appropriate arguments.
If we just make the function declaration (not definition) visible at file scope like so:
#include <iostream>
class A {
public:
friend std::ostream& operator<<(std::ostream& os, const A&) {
os << "Called\n";
return os;
}
};
std::ostream& operator<<(std::ostream& os, const A&);
class B {
public:
operator A() { return A(); }
};
int main()
{
A a;
std::cout << a;
B b;
std::cout << b;
}
This function declaration is once again found through ordinary unqualified name lookup, the user-defined conversion comes in during overload resolution, and the expected output of "Called" being printed twice is recovered.

because you use friend only if you want access to the members of the class but still they need to defined as a global function and then make them friend function of the class.

Related

Function template instantiation and friend declaration

I've just started learning templates in C++ and for practice purposes wrote this simple code
#include <iostream>
template<typename T>
class A;
template<typename T>
std::ostream& operator<<(std::ostream& out, A<T> x);
template <typename T>
class A
{
T m_x = 10;
public:
A(T x) : m_x{ x } {}
friend std::ostream& operator<< <T>(std::ostream& out, A x);
};
template<typename T>
std::ostream& operator<<(std::ostream& out, A<T> x)
{
out << "m_x = " << x.m_x;
return out;
}
int main()
{
A<int> a1{ 10 };
std::cout << a1 << '\n';
}
It works as expected, that is I get 10 as the output, but there is one thing that bothers me. At which point is the operator<< function instantiated? Does it happen at the point of creation of the a1 object (this is also the point where A<int> is implicitly instatiated, right?) or does it happen when I call the operator<< in std::cout << a1 << '\n'? My guess is that the second option is correct and I base it on this excerpt from cppreference which says that:
When code refers to a function in context that requires the function definition to exist, or if the existence of the definition affects the semantics of the program (since C++11), and this particular function has not been explicitly instantiated, implicit instantiation occurs.
But is it true that a friend declaration does not require the function definition to exist?
I'm sorry if this question is ill-pharased, I did my best to use the nomenclature right, but I'm just a beginner.
EDIT
What about this?
template <typename T>
class foo
{
T m_x;
friend void bar(foo x)
{
x.m_x = "123";
}
};
if I put a friend function definition inside a class, every instantiation of that class causes a new, ordinary function overload to be created that takes an argument of the current specialization, hence I would expect to see an error as soon as I write this: foo<int> x; but I don't get one... (for example, bar(x); causes the error)
I am not a language lawyer, so I'll try to answer with examples.
There are two aspects. First friend declaration.
A friend delcaration is a declaration. For example:
struct foo {
friend void bar();
};
int main() {
foo f;
}
Compiles and executes without any problem.
friend void bar(); declares a function bar. This functions is never defined. As long as we do not call it, thats not an issue. Of course, typically you would provide a definition, but if the function is never called you do not necessarily need to define it. Actually there are situations where having a declaration but no definition is on purpose, though thats out of scope of the quesiton.
Next, is templates and the question when member functions are instantiated. For that, consider this example:
#include <iostream>
template <typename T>
struct foo {
void bar() {
T x = "123";
}
};
int main() {
foo<int> x;
//x.bar();// error!
}
Compiles and executes without any problem.
Initializing an int with the string literal "123" is of course non-sense. Its only to provoke a compiler error when the method is instantiated. We can create an object of foo<int>. Though, we cannot call foo<int>::bar, because its not valid.
You can find many examples of methods of class templates that can only conditionally be instantiated in the standard library. For example std::map<key_t,value_t>::operator[]. It requires value_t to be default constructible, because it potentially has to default construct a value_t. You can use a std::map with a non-default-constructible value_t, you just cannot call its operator[]:
#include <map>
struct foo {
foo(int){}
};
int main() {
std::map<int,foo> x; // completely fine
x[1] = foo(1); // error
}
I spare you the complete error message. It is horrible, the essential part is:
error: no matching function for call to 'foo::foo()'
The overload of the operator<< in your case gives you an individual overload to every template classA<T>, so I can assume, that instantiation of operator<< can be with every instantiation of your class A<T>.
You can checkout this post, it can be useful in your case.

Is a non-member friend function overloaded operator inherited?

I have my parent class B and I overloaded the << operator. It seems my derived class D can use that operator, even tho I read everywhere that classes don't inherit friend functions from their parents. I used public inheritence by the way.
I am confused. Does this work because it is an overloaded operator, or any friend function is inherited by the child. Also if they are inherited, can I redefine them in any way?
If you have overloaded the friend operator<< for B, you may invoke that operator for D, even if it is not a freind of D:
class B {
public:
B(int i=0):v(i){}
private:
int v;
friend ostream& operator<< (ostream& os, const B& b);
};
class D:public B {
public:
D(string s=""s,int i=1) : B(i),v2(s){}
private:
string v2;
};
// access to the private members of B. B is accessed via a reference.
ostream& operator<< (ostream& os, const B& b){
return os<<b.v;
}
int main() {
B b;
D d;
cout << b <<endl; // calls operator<< for B
cout << d <<endl; // calls operator<< for the B sub-object of D
}
Online demo
For the D object, the B subject of D is used, since my code above passes argument by reference. If the overload would pass arguments by value instead of by reference, it would work as well, but the d object would be sliced into a B object.
In both case, the operator overload for the parent class is invoked.
You can overload the operator for the child class as well. But since friendship is not inherited, you'd need to define a new freindship if you need to access private members:
ostream& operator<< (ostream& os, const D& d){
//return os<<d.v<<d.v2; // not alloewed because D has no visibility on B's private members
return os << *static_cast<const B*>(&d) << d.v2;
}
Demo
The friendship for D is limited to D's private members and does not give access to B's private member. The usual way is to invoke the overload for B (here via a casting trick), and access the private member of D.
Of course, if operator<< only accesses public members we don't need any freindshop for the overload.

Hidden friends: declarations and definitions

In his recent blog post Anthony Williams talks about hidden friends. The main idea, if I understood it correctly, is that functions declared as friends cannot be found by ADL in certain situations. Simple example:
namespace N {
struct A {
friend void foo(A) { }
};
struct B {
operator A();
};
// (*)
void bar(A) { }
}
void func() {
N::A a;
bar(a); // OK, bar is found via ADL
foo(a); // OK, foo is found via ADL
N::B b;
bar(b); // OK, bar is found via ADL
foo(b); // NOT OK, foo cannot be found
}
In all examples in the blog post, the friend functions are defined inside classes. Is it possible to declare a friend function and then define it later at the point (*), so that it remains hidden? It looks like hidden friends can only be defined in the class scope (or in another compilation unit).
Hidden friends need to be fully defined inline, i.e., inside of the definition of class. Yes, if you define friends somewhere else, where definition can cause namespace visibility, it would break restrictions based on hidden friends to be found as match by ADL search only, and as such be candidate for overload resolution.
Further more in WG21 recommendations for specifying hidden friends,
is noted that hidden friends are fully defined inline, like in this snippet:
#include <ostream>
#include <compare>
class C {
friend ostream& operator << ( ostream&, C const& ) {}
friend auto operator <=>( C const&, C const& ) = default;
};
Hidden friends can be defined out of line, but then they are not hidden in that TU. As an example, consider this header:
class A {
// this is hidden friend defined inline
friend int operator+(A, int) { return 0; }
// this is hidden friend defined out of line
friend int operator+(int, A);
// not a hidden friend (see below)
friend int operator+(A, A);
};
int operator+(A, A); // this is no longer hidden friend in any TU
and then a separate cpp file:
#include "a.hpp"
// This is not a hidden friend in this TU, but is in other TUs.
int A::operator+(int, A) {
return 2;
}
Doing this is useful when you have operators/ADL customization points that depend on other large headers for their implementation.

Friend function and method with the same name

The following classes definitions declare a friend function providing an inline definition for it. I was trying to invoke the friend function from a class method with the same name of the friend function, but in order to make it work I have to access it from the enclosing namespace (which also requires a forward declaration, class C below). Why the name lookup works for class A and it doesn't work in class B? Note that the parameters of B::swap are different from those of its friend function.
#include <utility>
struct A {
A(int x) : v{ x } {}
friend void swap(A& x, A& y) { std::swap(x.v, y.v); }
void swapm(A& other) { swap(*this, other); }
private:
int v;
};
struct B {
B(int x) : v{ x } {}
friend void swap(B& x, B& y) { std::swap(x.v, y.v); }
void swap(B& other) { swap(*this, other); } // <-- This doesn't compile
private:
int v;
};
struct C;
void swap(C& x, C& y);
struct C {
C(int x) : v{ x } {}
friend void swap(C& x, C& y) { std::swap(x.v, y.v); }
void swap(C& other) { ::swap(*this, other); }
private:
int v;
};
int main()
{
A a1{ 1 }, a2{ 2 }; swap(a1, a2); a1.swapm(a2);
B b1{ 3 }, b2{ 4 }; swap(b1, b2); b1.swap(b2);
C c1{ 5 }, c2{ 6 }; swap(c1, c2); c1.swap(c2);
}
Whether it's a good idea or not, here's an explanation of why it's failing:
The compiler uses several different phases of processing to figure out what your program says. The reason that class B doesn't compile is because the failure that's occurring happens before the friend would be noticed. Let me explain:
When the compiler gets to the point where it's trying to figure out what swap means, it does a name lookup. It uses specific rules that specify where it should look. This is simplified, but basically it first looks for symbols defined in local scope, then in class scope, and then in enclosing (namespace, etc) scopes. It finds the one defined in class scope, and stops looking. That swap does not take those 2 parameters, so it the compilation fails.
The friend declaration, which allows the free function to access B's internals, acts as an additional declaration for the swap function that you've declared in the global namespace. These declarations would be considered by the compiler if it got to the point in name lookup where it was considering functions in the global namespace. In class B, the compiler has already stopped processing before it gets to this stage. (And the friend declaration would be necessary in an even later phase, when the compiler is working on compiling a version of the swap function that works with B objects, and wants to figure out, "in this function called swap that can take these 2 parameters; can I access B's internals?")
In class A, you're using a different name. The name lookup phase doesn't succeed until it locates your free swap function. In class C, you've given the name-lookup specific instructions, "hey, when you're looking up swap, look in global-namespace scope, and ignore the ones in local- and class-scope that you might find."
(Note: description of name-lookup and friend updated after #PeteBecker's comment.)
inline friend? Why not static in this case? And not friend? And then create a global one that calls the static. For me, this is a bad design more than an actual problem.
The method swap should be the one doing the work instead of the friend (because no need for a friend anymore):
struct C {
C(int x) : v{ x } {}
void swap(C& other) { std::swap(this->v, other.v); }
private:
int v;
};
void swap(C& x, C& y)
{
x.swap(y);
}

g++ 4.5 can't find a friend function

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
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 */
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;
}
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.