I used to name my test class as a friend in the class to be tested, in order to enable testing private fields. I noticed that the name of the class is not verified for existence. Is it by intention?
A friend class declaration that uses an elaborated type specifier with non-qualified name of the class is actually a declaration of that class. It introduces the class as a member of the enclosing namespace. It does not require it to be pre-declared
class C
{
friend class X; // OK, introduces '::X'
};
But if you use a qualified name in a friend class declaration, it will be subjected to a regular qualified name lookup. And it must refer to a previously declared name
class X {};
class C
{
friend ::X; // OK, refers to '::X'
friend ::Y; // Error, no '::Y' in sight
};
So, if you want your class name to be "verified for existence", use qualified names in friend declarations.
Is it by intention?
I think so. It's much like a forward declaration.
Usually the friend class needs a full declaration of the friended class, but not vice versa.
To force checking an existent (declared) type you can use
class MyClass {
friend FriendClass;
};
as mentioned in #bogdan's comment.
As a side note:
How to refactor the mostly not appropriate friend pattern, I recommend you to read my Q&A post: How can I remove refactor a «friend» dependency declaration properly?
Imagine if the friend class was required to exist. How would you structure your code? For testing you have that friend declaration in your code. When you build your shipping version you aren't going to ship the test code, so you have to remove the friend declarations and rebuild everything. Now you're shipping code that's different from the code that you tested.
Related
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.
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.
Does anyone know why typedefs of class names don't work like class names for the friend declaration?
class A
{
public:
};
class B : public A
{
public:
typedef A SUPERCLASS;
};
typedef A X;
class C
{
public:
friend class A; // OK
friend class X; // fails
friend class B::SUPERCLASS; // fails
};
It can't, currently. I don't know the reason yet (just looking it up, because i find it interesting). Update: you can find the reason in the first proposal to support typedef-names as friends: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1520.pdf . The reason is that the Standard only supported elaborated-type-specifiers. It's easy to allow only those, and say if the entity declared as friend is not declared yet, it will be made a member of the surrounding namespace. But this means that if you want to use a template parameter, you would have to do (a class is required then for example)
friend class T;
But that brought additional problems, and it was figured not worth the gain. Now, the paper proposes to allow additional type specifiers to be given (so that this then allows use of template parameters and typedef-names).
The next C++ version (due to 2010) will be able to do it.
See this updated proposal to the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf . It will not allow only typedef names, but also template parameters to be used as the type declared as friend.
AFAIK, In C++ typedef does not create a full-fledged synonyms when used in conjuction with classes. In other words, it's not like a macro.
Among the restrictions is that the synonym cannot appear after a class or struct prefix, or be used as a destructor or constructor name. You also cannot subclass the synonym. I would bet that is also means you can't friend it.
I tried in the VC++ 8.0 the code:
...
class C
{
public:
friend class A;
friend X;
friend B::SUPERCLASS;
};
...
It is compiled without errors.
I am not aware whether it MS specific or not.
A typedef defines a type. Friend decls declare friend classes or functions (substantially scopes), which then have "access" to the non public area of the declaring class...
Primitives, i.E. a float or an int* don't define a scope with code etc.,
they don't "use" the class anyway.
Don't forget, you can also "pack" call conventions, alignment attribs and other compiler specific stuff in a typedef, i.e. multiple vector TYPES implemented by the same class but with distinct alignment attribs. => A type is not a class, but vice versa.
IMHO, declaring a friend typedef can be useful, but when "class typedefs" from anywhere can be set as friend, the friendships can become extremely incomprehensible and therefore error-prone, especially where templates are used excessively.
Invalidating a single typedef can mess up the whole project due to widespread dependencies.
Template friends and the 0x template typedefs are useful, but don't relax the rules of a friend declaration.
I don't know of any proposal concerning friend typedefs.
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?
Does anyone know why typedefs of class names don't work like class names for the friend declaration?
class A
{
public:
};
class B : public A
{
public:
typedef A SUPERCLASS;
};
typedef A X;
class C
{
public:
friend class A; // OK
friend class X; // fails
friend class B::SUPERCLASS; // fails
};
It can't, currently. I don't know the reason yet (just looking it up, because i find it interesting). Update: you can find the reason in the first proposal to support typedef-names as friends: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2003/n1520.pdf . The reason is that the Standard only supported elaborated-type-specifiers. It's easy to allow only those, and say if the entity declared as friend is not declared yet, it will be made a member of the surrounding namespace. But this means that if you want to use a template parameter, you would have to do (a class is required then for example)
friend class T;
But that brought additional problems, and it was figured not worth the gain. Now, the paper proposes to allow additional type specifiers to be given (so that this then allows use of template parameters and typedef-names).
The next C++ version (due to 2010) will be able to do it.
See this updated proposal to the standard: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf . It will not allow only typedef names, but also template parameters to be used as the type declared as friend.
AFAIK, In C++ typedef does not create a full-fledged synonyms when used in conjuction with classes. In other words, it's not like a macro.
Among the restrictions is that the synonym cannot appear after a class or struct prefix, or be used as a destructor or constructor name. You also cannot subclass the synonym. I would bet that is also means you can't friend it.
I tried in the VC++ 8.0 the code:
...
class C
{
public:
friend class A;
friend X;
friend B::SUPERCLASS;
};
...
It is compiled without errors.
I am not aware whether it MS specific or not.
A typedef defines a type. Friend decls declare friend classes or functions (substantially scopes), which then have "access" to the non public area of the declaring class...
Primitives, i.E. a float or an int* don't define a scope with code etc.,
they don't "use" the class anyway.
Don't forget, you can also "pack" call conventions, alignment attribs and other compiler specific stuff in a typedef, i.e. multiple vector TYPES implemented by the same class but with distinct alignment attribs. => A type is not a class, but vice versa.
IMHO, declaring a friend typedef can be useful, but when "class typedefs" from anywhere can be set as friend, the friendships can become extremely incomprehensible and therefore error-prone, especially where templates are used excessively.
Invalidating a single typedef can mess up the whole project due to widespread dependencies.
Template friends and the 0x template typedefs are useful, but don't relax the rules of a friend declaration.
I don't know of any proposal concerning friend typedefs.