some friend functions don't follow the rule - c++

For the following snippet:
class A{
friend void f(){};
public:
A(){f();} //error
};
class B{
friend void f(void* ptr){};
public:
B(){f(this);} //no error
};
According to the rule that although friend functions can be defined inside a class, yet they are not visible until they are declared somewhere outside the class scope, the error in the definition of class A is explained.
But I am confused why the snippet for class B doesn't produce the same error as class A's.
Please can anyone tell me about this?

"Not visible" is a bit of an over-simplification. With only an in-class definition, a friend function can't be found by qualified or unqualified lookup, which is why the first snippet fails.
However, it can be found by argument-dependent lookup (ADL), so you can call it with an argument involving a type that's scoped in the same namespace as the function.
In this case, the argument type is B*, scoped in the global namespace. The friend function is scoped in the namespace containing the class that declares it - also the global namespace. So ADL will look in the global namespace for functions called f, find the friend function, and use that.

Related

Function overload outside class not seen

Consider following code snippet:
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
foo(Bar::A);
}
};
It fails to compile, the message from gcc 9.2 is:
:12:19: error: no matching function for call to 'Baz::foo(Bar)'
12 | foo(Bar::A);
|
I don't suspect it is a bug since clang 10 also fails. I have two questions regarding this situation:
Where does standard define bahaviour for such overloads?
What are the possible reasons that compiler behaviour is specified that way?
live example
The call to foo inside Baz::foo() will only look up names inside the class. If you mean to use the foo declared outside the class Baz, you need to use the scope-resolution operator, like this:
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void foo() {
::foo(Bar::A); // looks up global 'foo'
}
};
Note that the unscoped call to foo fails because there is a Bar::foo that is found in the closest scope. If you name the function differently, then no function is found in Bar, and the compiler will look in the outer scope for the function.
enum class Bar {
A
};
void foo(Bar) {}
struct Baz {
void goo() { // not 'foo'
foo(Bar::A); // this is fine, since there is no 'Bar::foo' to find
}
};
Here's the quote from cppreference for a class definition.
e) if this class is a member of a namespace, or is nested in a class that is a member of a namespace, or is a local class in a function that is a member of a namespace, the scope of the namespace is searched until the definition of the class, enclosing class, or function. if the lookup of for a name introduced by a friend declaration: in this case only the innermost enclosing namespace is considered, otherwise lookup continues to enclosing namespaces until the global scope as usual.
Of course, this only applies to class definitions, but for member functions (which is your example), it says
For a name used inside a member function body, a default argument of a member function, exception specification of a member function, or a default member initializer, the scopes searched are the same as in [class definition], ...
So the same logic applies.
According to the rule of unqualified name lookup, from the standard, [basic.lookup.unqual]/1,
(emphasis mine)
In all the cases listed in [basic.lookup.unqual], the scopes are searched for a declaration in the order listed in each of the respective categories; name lookup ends as soon as a declaration is found for the name.
That means the name foo is found at the class scope (i.e. the Baz::foo itself), then name lookup stops; the global one won't be found and considered for the overload resolution which happens later.
About your 2nd question, functions can't be overloaded through different scopes; which might cause unnecessary confusion and complexity. Consider the following code:
struct Baz {
void foo(int i) { }
void foo() {
foo('A');
}
};
You know 'A' would be converted to int then passed to foo(int), that's fine. If functions are allowed to be overloaded through scopes, if someday a foo(char) is added in global scope by someone or library, behavior of the code would change, that's quite confusing especially when you don't know about the adding of the global one.

Why can't forward declared friend class be referred in the class?

The following code doesn't compile:
struct X {
friend class Y;
Y* ptr;
};
The cppreference describes the situation as
... If the name of the class that is used in the friend declaration is
not yet declared, it is forward declared on the spot.
If the "spot" means where the friend relationship is declared, then it should be fine to declare the member Y* ptr. Why doesn't it compile? Where in the standard prohibits this?
This is a mistake on the site. It contradicts the standard, which says that friendship declaration is not a substitute for a forward declaration:
7.3.1.2.3 Every name first declared in a namespace is a member of that namespace. If a friend declaration in a non-local class first declares a class, function, class template or function template the friend is a member of the innermost enclosing namespace. The friend declaration does not by itself make the name visible to unqualified lookup or qualified lookup.
The part about the name not being visible to unqualified or qualified lookup essentially means that the name does not behave like a forward declaration.
In addition to the answer of #dasblinkenlight, a note in 3.3.2 Point of declaration lit. 10 explicitly says that a friend declaration does not introduce (and therefore not "forward declare") a class name:
10 [ Note: Friend declarations refer to functions or classes that are
members of the nearest enclosing namespace, but they do not introduce
new names into that namespace ([namespace.memdef]).
One way to fix this code is to simply add class keyword:
struct X {
friend class Y;
class Y* ptr;
};
This will forward declare class Y at the global scope, if X is in the global scope.

What is the reason to we can not define friend function in local class?

I have a following snippet code of c++. Declared a class inside main() function.
What is the reason to we can not define friend function in local class?
#include<iostream>
int main()
{
class Foo
{
void foo() {} // Ok
friend void Bar(){}; // Error
};
}
There's a practical reason. First and foremost, an inline friend definition cannot be found by either qualified or unqualified lookup. It can only by found by ADL. So if we take the class from your example, put it in global scope and try to call Bar:
class Foo
{
friend void Bar(){};
void foo() {
Bar();
}
};
We'll be notified that Bar was not declared in that scope. So if it was in a local class. You can't call it from the members. You can't call it inside the function. The only way you may call it involves either some hoops or ADL. So the language just doesn't allow for it. It's not deemed a useful feature.
There is no convincing technical reason for this. ADL can't find it, you say? Well, that's basically part of the question: why can't ADL find it? Just extend ADL to make it find it.
One design-level reason for this limitation is probably rooted in the language treatment of unqualified names in friend declarations.
Unqualified names used in friend declarations in local classes refer to names from nearest enclosing non-class scope. This treatment of unqualified names is critically important, since this is the only way local classes can refer to each other (since for obvious reasons, local classes do not have qualified names)
int main()
{
class B;
class A {
int x;
friend B; // refers to local `B`
};
class B {
void foo(A &a) { a.x = 42; }
};
}
This rule is also applied to friend function declarations with unqualified names. C++ does not have local functions, but such friend declarations can still refer to a local non-defining declaration of a function (which is perfectly legal)
void foo() {}
int main()
{
void foo(); // refers to `::foo`
class A {
friend void foo(); // refers to local `foo`, which is `::foo`
};
}
Now, what would you propose should happen when one defines a friend function in a local class (using an unqualified name, of course)? What function is introduced by such a declaration? Into what scope, specifically? By definition, it is not a member of the class, since friend declarations do not introduce class members. It cannot be a member of the nearest enclosing local scope, since that would make it a local function and C++ does not support local functions.
We cannot just uniformly change the behavior of all unqualified names in friend declarations and say that they should now refer to names in the nearest enclosing namespace scope, since that would leave as with no way to refer to local classes (as shown above).
The only way out of this situation is to make only in-class friend function definitions refer to (and define) functions in the nearest enclosing namespace scope. Such functions would only be callable through [modified] ADL (and let's say we are OK with that). But that would mean that we'd have to give different treatment to unqualified names in friend function definitions (as opposed to non-defining friend declarations). This would be rather inelegant and confusing. So, the language authors decided against it.
Note that importance of this might have increased notably after C++14, which gave us deduced auto return types in functions. After that local classes became not even nearly as "local" as they used to be
auto foo()
{
struct S // Local class
{
void bar() {}
};
return S();
}
int main()
{
auto a = foo();
a.bar(); // An object of local class used outside of its original scope
typedef decltype(a) S; // Local type is "stolen" from its original scope
S b; // and used to freely declare objects in a completely
b.bar(); // different scope
}
Because member functions of a local class have to be defined entirely inside the class body and friend function not a member function. We declared friend functions inside class and defined outside of class.
According to cppreference:
Local classes
A local class cannot have static members
Member functions of a local class have no linkage
Member functions of a local class have to be defined entirely inside the class body
Local classes other than closure types (since C++14) cannot have member templates
Local classes cannot have friend templates
Local classes cannot define friend functions inside the class definition
A local class inside a function (including member function) can access the same names that the enclosing function can access.

Is the friend declaration a real declaration?

C++ Primer says:
It is important to understand that a friend declaration affects access but is not a declaration in an ordinary sense.
So friend declaration should offer access authority only to the friend class/function, it is not a real declaration.
However, I tried this program, it complied successfully and outputs 2 in GCC 5.2.0, what's wrong?
#include <iostream>
class Tmp {
public:
Tmp(int a) : a_(a) {};
private:
int a_;
friend void p(Tmp a) { std::cout << a.a_ << std::endl; }
};
// void p(Tmp a); I commented it, so there is not any declaration statement for p(Tmp a).
int main(void) {
Tmp a(2);
p(a);
return 0;
}
A friend declaration is a real declaration in the technical sense: it is a declaration according to the grammar of the C++ language. The keyword friend is a specifier that modifies a declaration.
If you really want to know what the book means, you should just look at the immediately preceding text.
Classes and nonmember functions need not have been declared before they are used in a friend declaration. When a name first appears in a friend declaration, that name is implicitly assumed to be part of the surrounding scope. However, the friend itself is not actually declared in that scope (§7.2.1, p. 270).
Even if we define the function inside the class, we must still provide a declaration outside the class itself to make that function visible. A declaration must exist even if we only call the friend from members of the friendship granting class.
The friend declaration is different from a typical declaration because most declarations introduce the names they declare into the scope in which they are found, and then those names may be immediately used:
int x; // introduces the name x into this scope
x = 0; // lookup of "x" finds the name just declared
A friend declaration introduces the name declared into the nearest enclosing namespace, not the class in which the friend declaration is found. So it is unusual in that sense. However, even more unusually, the name introduced by a friend declaration is not visible to either qualified or unqualified name lookup until the same name is declared at the nearest enclosing scope.
In other words, you may not be able to start using the name immediately after the friend declaration. This is probably what the book means when it says the friend declaration is not a declaration in the ordinary sense.
Here is a simple example:
#include <cstdio>
class C {
friend void hello() { std::puts("Hello, world!"); }
};
int main() {
hello();
}
This program is ill-formed because hello was not declared in the global namespace before being called. http://coliru.stacked-crooked.com/a/3ae525122312c96c
Your example only happens to work because there is a special rule that argument-dependent lookup finds friends declared inside associated classes even if they haven't been declared at namespace scope yet. In the call p(a), since a has the class type Tmp, the class Tmp is an associated class.
Friend declarations are as much a declaration as any other, as in they introduce a name; perhaps C++ Primer should have chosen its words better.
A friend declaration however is not visible for qualified or unqualified lookup (in the absence of other declarations of the same name). Your example works due to ADL, but as you can see from the following a friend declaration alone will not make the name available for any other kind of lookup:
struct Tmp {
friend void p(Tmp);
friend void q();
};
int main() {
Tmp a;
p(a); // Argument-dependant lookup ==> ok!
q(); // Unqualified lookup ==> nope
::q(); // Qualified lookup ==> also nope
}
test.cpp: In function 'int main()':
test.cpp:9:9: error: 'q' was not declared in this scope
q();
^
test.cpp:10:7: error: '::q' has not been declared
::q();

Friends confusion

$11.4/5 - "[...]A friend function defined in a class is in the (lexical) scope of the class in which it is defined[...]"
What does this statement mean?
struct A{
typedef int MYINT;
void f2(){f();} // Error, 'f' is undefined
friend void f(){MYINT mi = 0;} // Why does this work, shouldn' it be A::MYINT?
void f1(){f();} // Error, 'f' is undefined
};
int main(){}
What is confusing here is that the call to 'f' from 'A::f1' is quiet understandable. However why is call to 'f' from 'A::f2' ill-formed, when a friend is in 'lexical' scope of the befriending class? What does 'lexical' scope mean?
At the same type why is the usage of 'MYINT' in 'f' OK? Shouldn't it be 'A::MYINT'?
If I add a parameter of type 'A *' to 'f', then both 'f1' and 'f2' are able to find 'f' because of ADL. This is understandable.
You have quoted only part of §11.4/5. According to it f() should be declared out of class first (function should have namespace scope). Try this:
void f(); // declare it first
struct A{
typedef int MYINT;
void f2(){f();}
friend void f(){MYINT mi = 0;} // definition of global f, a friend of A
void f1(){f();}
};
As for second question, it is ok because of quoted by you part of §11.4/5. f() obeys the same rules for name binding as a static member function of that class and has no special access rights to members of an enclosing class.
Here is my interpreation of one part of my query which is
"Why MYINT" can be referred to as
"MYINT" instead of "A::MYINT"?
$3.4.1/9 states - "Name lookup for a
name used in the definition of a
friend function (11.4) defined inline
in the class granting friendship shall
proceed as described for lookup in
member function definitions. If the
friend function is not defined in the
class granting friendship, name lookup
in the friend function definition
shall proceed as described for lookup
in namespace member function
definitions."
In our case, the name to be looked up is 'MYINT' which is a unqualified name. The lookup for this name inside the definition of the friend 'f' which is defined inline in the class would would be done in the same was as it would be for member functions of 'A'.
Is my understanding correct?