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();
Related
I'm a newbie reading the C++ Primer book. It says:
A friend declaration only specifies access. It is not a general declaration of the function. If we want users of the class to be able to call a friend function, then we must also declare the function separately from the friend declaration. To make a friend visible to users of the class, we usually declare each friend (outside the class) in the same header as the class itself.
But I just found that this is not the case for friend operator functions defined inside the class body. In the following code, f could not be found but operator+ is found:
struct X
{
friend void f()
{
// friend functions can be defined in the class
// this does NOT serve as a declaration, even though this is already a definition
// to use this function, another declaration is REQUIRED
}
friend X operator+(const X & x1, const X & x2)
{
// this stuff serves as declaration somehow
return {x1.v + x2.v};
}
void foo()
{
f(); // ERROR: no declaration for f
X tmp = X {1} + X {2}; // CORRECT
}
int v;
};
Could someone tell me what makes this difference?
I am using g++ (Ubuntu 9.3.0-17ubuntu1~20.04) 9.3.0, as a reference.
I have searched many questions involving friend declaration and definition on StackOverflow but did not find an answer on this. Sorry if this question is duplicated.
The difference is the operator+ takes X as parameter, then ADL could find the name; f takes nothing, ADL can't help any.
(emphasis mine)
Names introduced by friend declarations within a non-local class X become members of the innermost enclosing namespace of X, but they do not become visible to ordinary name lookup (neither unqualified nor qualified) unless a matching declaration is provided at namespace scope, either before or after the class definition. Such name may be found through ADL which considers both namespaces and classes.
Even if we define the function inside the class, we must still provide a declaration outside of 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. This means in your example, you should forward declare the function f as shown below:
//forward declare f
void f();
struct X
{
//no ADL here since this function f has no parameters of type X. So we also need to declare this outside struct X which we did by providing forward declaration
friend void f()
{
}
void foo()
{
f(); // WORKS NOW because of the forward declaration
X tmp = X {1} + X {2}; //operator+ found using ADL
}
//other members here
};
The output of the program can be seen here.
The reason why the call to operator+ works is because of ADL which stands for argument dependent lookup. In particular, operator+ can be found using ADL since it has parameters of type X. So in this case, you do not need to explicitly declare operator+ outside struct X.
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.
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.
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.
$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?