The scope of in-class-defined friend function? - c++

A few days ago I asked a question about the scope of in-class-defined friend functions (Which scope does an in-class-defined friend function belong to?), and I get to know that the function is in the scope of the enclosing namespace but won't be searchable until explicitly declared outside the class (ADL is an exception).
Today I found some relevant statements in the C++ standard (section 11.3):
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. [ Example:
class M {
friend void f() { } // definition of global f, a friend of M,
// not the definition of a member function
};
—end example ]
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).
We can see that there are two scope-related statements here: "has namespace scope" and "is in the (lexical) scope of the class in which it is defined". I'm confused here. If the former relates to my previous question (Which scope does an in-class-defined friend function belong to?), then what does the latter stand for?

A "namespace-scope function" is a function that is a member of a namespace (i.e the "scope" here means the "home scope" of the function).
The later statement links to 3.4.1, which has to say
Name lookup for a name used in the definition of a friend function (11.3) defined inline in the class granting friendship shall proceed as described for lookup in member function definitions.

Related

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.

some friend functions don't follow the rule

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.

Is it possible to bring global function into the overload resolution with member function?

Here is the corresponding question, what I want to know is, Is it possible to bring global function into the overload resolution with member function?
I tried in 2 ways, but both don't work:
void foo(double val) { cout << "double\n";}
class obj {
public:
using ::foo; // (1) compile error: using-declaration for non-member at class scope
void callFoo() {
using ::foo; // (2)will cause the global version always be called
foo(6.4);
foo(0);
}
private:
void foo(int val) {cout << "class member foo\n"; }
};
I doubt you can make the compiler call one or the other based on the type. You can of course use a local wrapper function, something like this:
void callFoo() {
foo(6.4);
foo(0);
}
private:
void foo(double val) { ::foo(val); }
The wrapper function should nicely inline into nothing, so there is no actual overhead when compiled with optimisation.
Or don't call the member and the global function the same name, which makes life a whole lot easier!
This is plain old unqualified name lookup, specified in §3.4.1 [basic.lookup.unqual]:
1 In all the cases listed in 3.4.1, 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. If no
declaration is found, the program is ill-formed.
8 For the members of a class X, a name used in a member function
body, in a default argument, in an exception-specification, in the
brace-or-equal-initializer of a non-static data member (9.2), or in the definition of a class member outside of the definition of X,
following the member’s declarator-id, shall be declared in one of
the following ways:
before its use in the block in which it is used or in an enclosing block (6.3), or
shall be a member of class X or be a member of a base class of X (10.2), or
if X is a nested class of class Y (9.7), shall be a member of Y, or shall be a member of a base class of Y (this lookup applies
in turn to Y’s enclosing classes, starting with the innermost
enclosing class), or
if X is a local class (9.8) or is a nested class of a local class, before the definition of class X in a block enclosing the definition
of class X, or
if X is a member of namespace N, or is a nested class of a class that is a member of N, or is a local class or a nested class within
a local class of a function that is a member of N, before the use of
the name, in namespace N or in one of N’s enclosing namespaces.
Note first that name lookup stops as soon as a declaration is found. So if you have using ::foo; in callFoo(), lookup for foo will end there and never touch the second bullet point; if you don't have it, lookup for foo will find the member foo() at the second bullet point and never search elsewhere. The way unqualified name lookup is specified means that you will either find class members or non-class-members, but never both.
This is also noted in §13.1.1.1 [over.call.func]/p3:
In unqualified function calls, the name is not qualified by an -> or .
operator and has the more general form of a primary-expression. The
name is looked up in the context of the function call following the
normal rules for name lookup in function calls (3.4). The function
declarations found by that lookup constitute the set of candidate
functions. Because of the rules for name lookup, the set of candidate
functions consists (1) entirely of non-member functions or (2)
entirely of member functions of some class T. In case (1), the argument list
is the same as the expression-list in the call. In case (2), the
argument list is the expression-list in the call augmented by the
addition of an implied object argument as in a qualified function
call.
A using-declaration at class scope must name a base class member (§7.3.3 [namespace.udecl]/p3):
In a using-declaration used as a member-declaration, the
nested-name-specifier shall name a base class of the class being defined.
What it appears you are trying to do is use the parameter type to choose the correct overload, and to bring the external foo into your class or member function.
Bringing it into the class is easy. You just declare another overload as a class member that forwards to the external one.
Bringing into the function is tricky but can be done by use of helper functions e.g. fooCaller( double ) and fooCaller( int ) which you can call from callFoo.
If you don't want to expose these to the external user, i.e. hide them away in the cpp file, it can be done but is trickier, due to the fact that foo in your class is private. You would have to have your callFoo function pass in the private function as a member function to "call" for the int overload.
You cannot do that probably because member functions has different signature visible by compiler, which is
void foo(double)
vs
void obj::foo(int)

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?