friendship scope c++ - c++

In section 11.5.1 of "The C++ Programming Language", Bjarne Stroustrup writes:
Like a member declaration, a friend declaration does not introduce a name into an enclosing scope.
For example:
class Matrix
{
friend class Xform;
friend Matrix invert (const Matrix &);
//..
};
Xform x; // error: no Xform in scope
Matrix (*p) (const Matrix &) = &invert; // error: no invert() in scope
For large programs and large classes, it is nice that a class doesn’t ‘‘quietly’’ add names to its enclosing scope. For a template class that can be instantiated in many different contexts (Chapter 13), this is very important.
However, the next section then goes on to say that the class must have been previously defined, or defined in the non-class scope immediately enclosing the class that is declaring it a friend.
My question is that because of the fact that the class needs to be previous defined or defined in the nonclass scope immediately enclosing the class that is declaring it a friend, then in the first example Xform could not be out of scope, as presumably the class would have been defined before the definition of the Matrix class. Furthermore, I can't think of a situation which, given the restriction that the friend class needs to be previously defined or defined immediately after the granter's class, that the friend class will not be in scope!
Secondly, is my interpretation of Bjarne in this section correct, in that:
For friend CLASSES only, friend class must have been previously defined in an enclosing scope, OR defined immediately after the non-class scope.
For a function, must have been previously declared in an enclosing scope, OR it can also be found by having an argument of type == 'the friendship granter's' class?

You're right that Xform would need to have been defined before Matrix if the example code was supposed to work. But it wasn't supposed to work. It was an example of bad code — code that tried to have the friend declaration introduce new names into the program, and then use those names to declare a variable and initialize a pointer.
That was the entire standalone example. It wasn't just an excerpt where you were supposed to imagine additional code before or after the given code, such as definitions for Xform and invert.
Your first paraphrase is not quite correct. The definition of the friend class does not need to immediately follow the class who granted it friendship. It needs to be defined in the immediately enclosing scope. Essentially, it should be defined in the same scope as the class it's friends with. The example after the one you cite illustrates it:
class AE { /* ... */ }; // not a friend of Y
namespace N {
class X { /* ... */ }; // Y's friend
class Y {
friend class X;
friend class Z;
friend class AE;
};
class Z { /* ... */ }; // Y's friend
}
Although Y says that AE is its friend, it's not referring to the AE class declared earlier because namespace N is the immediately enclosing scope of Y and AE isn't declared there. Instead, the friend declaration must refer to some other AE class that's going to be defined in namespace N elsewhere in the program. (However, it doesn't need to be defined anywhere at all; classes can say they are friends with things that don't exist, and the program won't care. The programmers will care, though, because they'll waste time trying to find the right AE class in the source code.)
You're also wrong on your second paraphrase. The function doesn't have to have been previously declared in an enclosing scope. It just has to be declared eventually. Consider the opening example of section 11.5, where operator* is listed as a friend of both Vector and Matrix classes before the operator has been either declared or defined.
Furthermore, for the friend function to be found, it doesn't have to have arguments equal to the class's type. Stroustrup says the function "can be found through its arguments," and then refers you to section 8.2.6 for what he means by that. That's the section on name lookup.

An example of when Matrix is in scope, XForm isn't, yet there is an XForm class defined which is the friend of Matrix:
1.h
------------------------
namespace Foo
{
class Matrix
{
friend class XForm;
};
}
1.c
------------------------
#include 1.h
// XForm not in scope
// implement Matrix
2.h
------------------------
namespace Foo
{
class XForm
{
};
}
main.c
#include 1.h
#include 2.h
int main()
{
// both XForm & Matrix in scope here
}
Is this correct?

I don't know if I understand your question, but I think Bjarne thought you need to define the class (say Xform) outside Matrix if you want to use it (imagine it is some helper class you put in a header file that you don't #include in all .cpp files that #include the file with Matrix). You needn't define it if you never mention it :)
In case of functions, the situation is similar. However, there is a difference, that it can be even defined with the friend declaration (=inside the Matrix class) and, as you say, "be found by having an argument of type == 'the friendship granter's' class" (or have argument type that is a nested class thereof), by Koenig lookup.

The idea of a friend function is when you have a private class so that normally other classes cannot access what's inside - you're making a black box, BUT you want to specifically name functions that are outside that are exceptions to that rule. I think it should be thought of as not having much to do with scope, or if anything, defining a special kind of scope.
Something defined as a friend would have to be defined elsewhere, otherwise it's not a friend - it's nothing - it doesn't exist.
Was that the question?

Related

C++ friend operator definition inside class body serves as function declaration?

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.

Member access control for friend function defined inside class in C++

I understand that the following C++ code snippet should produce an error in the definition of g, because p.t.x is private and cannot be accessed there.
class P {
class T {
int x;
friend class P;
};
T t;
friend void g(P &p);
};
void g(P &p) { p.t.x = 42; }
What puzzles me is the next snippet. It differs only in the fact that the definition of the friend function g now occurs inside class P.
class P {
class T {
int x;
friend class P;
};
T t;
friend void g(P &p) { p.t.x = 42; }
};
Clang++ (both 6.0.0-1ubuntu2 and Apple version clang-1100.0.33.8) compiles the latter with no error, whereas GNU C++ (7.5.0-3ubuntu1~18.04) produces the same error as in the former snippet.
I understand that the function g defined in the latter case is not in the same scope
as the one defined in the former (cf. a related question and an older longer discussion) and it's only visible through ADL. But I think what I'm asking here is different: should the declaration friend class P in class T extend to the body of friend function g or not?
The relevant part of the C++ standard (§11.3 or §11.9.3 in more recent drafts) states that:
7 ... 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 (6.5.1).
So I understand that Clang++ and GNU C++ interpret differently what is meant by "lexical scope" (see also this answer to the previous related question). Clang++ seems to compile g as if it were a friend of class T, probably because it's in the lexical scope of class P which is a friend of class T, whereas GNU C++ does not.
Is there a bug in one of the two compilers?
If yes, which one?
Regardless of the answers to the previous questions, isn't this something that the standard should formalise better?
This looks like CWG1699 (which is still open).
1699. Does befriending a class befriend its friends?
According to 14.3 [class.friend] paragraph 2,
Declaring a class to be a friend implies that the names of private and protected members from the class granting friendship can be accessed in the base-specifiers and member declarations of the befriended class.
A friend declaration is a member-declaration, but it is not clear how far the granting of friendship goes in a friend declaration. For example:
class c {
class n {};
friend struct s;
};
struct s {
// #1 and #2 are not relevant for this question
friend void f() { c::n(); } // #3
};
In particular, if a friend function is defined inside the class definition, as in #3, does its definition have access to the private and protected members of the befriending class? Implementations vary on this point.
For starters - disclaimer: this is my interpretation of the standard and even though I think it's the right one, one can't be sure what was really meant.
tl;dr
Yes.
IMO clang++
If you look below you will notice it is formalised pretty good.
Full answer
Having said that I think there are two relevant quotes from the standard. First is this:
11.9 Member access control
1 A member of a class can be
(1.1) - private; that is, its name can be used only by members and friends of the class in which it is declared.
and the second is:
11.9.3 Friends [class.friend]
1 A friend of a class is a function or class that is given permission to use the private and protected member names from the class.
A class specifies its friends, if any, by way of friend declarations.
Such declarations give special access rights to the friends, but they do not make the nominated friends members of the befriending class.
From these two one can deduce a few things. But the most important one is that even inline friend cannot access private members of class defined inside befriended class. Why? Because it is neither member nor friend of the nested class. And from that it seems the g++ is right here.

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.

Member's potential scope for struct vs namespace

Referring to this code:
namespace Y {
char f() { return y; } // error: y was not declared in this scope
char y;
}
struct X {
char f() { return x; } // OK
char x;
};
As per basic.scope.namespace#1:
The declarative region of a namespace-definition is its
namespace-body. Entities declared in a namespace-body are said to be
members of the namespace, and names introduced by these declarations
into the declarative region of the namespace are said to be member
names of the namespace. Its potential scope includes its namespace from the name's point of declaration onwards.
QUESTIONS
Is it correct to say that the error was due to the fact that Y::y is not yet declared in Y::f()?
I can't figure why there isn't a "reodering" for namespace members during declaration while for struct there is. What could be the reason for disallowing such behavior? Does the standard says something similar?
Is it correct to say that the error was due to the fact that Y::y is not yet declared in Y::f()?
Yes.
I can't figure why there isn't a "reodering" for namespace members during declaration while for struct there is. What could be the reason for disallowing such behavior? Does the standard says something similar?
The biggest hindrance for namespaces as opposed to classes, is that they are never "closed". You can always add members to a namespace by re-opening it in another translation unit and declaring more stuff in it. A class declaration however, for all its members, must appear entirely in a single translation unit. And there is no adding to it later.
[class.mem]/1
The member-specification in a class definition declares the full set
of members of the class; no member can be added elsewhere.
The problem for namespaces is intractable. But classes only require a little more, quite localized, work.
It is therefore much easier, both to a language designer and a compiler writer, to demand namespace declarations appear before they are used.
You should also note that you can only use other members of the class in only a specific set of places inside the definition.
[class.mem]/6
A class is considered a completely-defined object type ([basic.types])
(or complete type) at the closing } of the class-specifier. Within the
class member-specification, the class is regarded as complete within
function bodies, default arguments, noexcept-specifiers, and default
member initializers (including such things in nested classes).
Otherwise it is regarded as incomplete within its own class
member-specification.
You are mistaken thinking that for structures there is "reordering".
Consider the following structure definition.
#include <iostream>
struct A
{
char s[N];
enum { N = 10 };
};
int main()
{
return 0;
}
The compiler will issue an error because the name N is not yet declared when it is used in the array declaration. So neither "reordering" exists in the class scope. As for member functions then names used within a member function are at first searched in the class scope.
Moreover a name declared in a namespace can hide the same name declared in the outer namespace. As result the "reordering" breaks scopes of variables.

Scope resolution operator being used twice

namespace libzerocoin {
//Commitment class
Commitment::Commitment::Commitment(const IntegerGroupParams* p,
const Bignum& value): params(p), contents(value) {
this->randomness = Bignum::randBignum(params->groupOrder);
this->commitmentValue = (params->g.pow_mod(this->contents, params->modulus).mul_mod(
params->h.pow_mod(this->randomness, params->modulus), params->modulus));
}
I just encountered this function definition on GitHub.
I assume that the second and the third "Commitment" refer to the class name and constructor, but I can't figure out the meaning of the first. I am sure that it does not refer to the namespace because that name is different. I have seen the scope resolution operator being used twice in examples, but those refer to nested namespaces.
In C++ classes have the feature of having their name injected into their scope ([class]/2):
The class-name is also inserted into the scope of the class itself;
this is known as the injected-class-name. For purposes of access
checking, the injected-class-name is treated as if it were a public
member name.
And the code snippet you showed makes use of it. In certain contexts Commitment::Commitment names the class itself, and in others names the c'tor. Only the last Commitment(, where you open the parentheses, begins the c'tor definition.
And it can look much much worse:
struct foo {
foo();
};
foo::foo::foo::foo() = default;
Which you can see is valid C++ Live.