Any way to declare multiple friend classes in one statement? - c++

I wish to declare multiple C++ friend classes in one statement as below, just to tidy the code. The reason is, in my actual application, there will be three or four friend classes, so it'll be messier than this sample.
Is it possible in any way?
class A{
friend class B, C; // this doesn't work
// friend class B;
// friend class C; // these two would be okay
};
class B{};
class C{};

No you need to write it out longhand.
I can't think of a grammatical reason why your notation couldn't be introduced. (C++17 allows you to shorten the namespace notation, for example, so you're idea is not without precedent).
Why don't you propose your idea to the C++ standards committee?
Of course there will be counter-arguments centred around compiler complexity.

Whole classes - you can't, as friend declaration in that case also acts like forward declaration and that would be conflicting syntax.
But you can declare members of various classes as friends in one statement, if those are already complete:
#include "class_b.h"
#include "class_c.h"
class A {
friend B::B(), C::~C();
};

Related

Friend declaration not working with typedef [duplicate]

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.

Why can't a class have a pointer to an instance of another class without forward declaration?

I know it's impossible to do
class foo{
foo bar;
};
Because the compiler wouldn't know how much memory to prepare for foo.
But consider:
class A{
B::C* foo;
};
class B{
class C{
};
};
It seems quite reasonable that the compiler would know exactly the size of A no matter the definition of the C. Why isn't this possible then? (Does the standard forbids that explicitly? for what?)
I got a very crude way by-pass the constraint that is to treat foo as a uintptr_t, then reinterpret_cast it back to C, this is just to show that I really don't get the (objective) reason, and I know it's a really really bad practice if used without decent reason.
Finally it turns out to be forbidden by the standard.
One big challenge is following:
class other {};
namespace N {
class foo {
other* p;
};
class other {};
}
Which other* should be considered? Too much of work for compiler. Though we can be explicit by ::other or N::other, it still creates confusion in above case.
TL;DR: That is because the standard dicates the syntax to be so. Unfortunately it's as simple as that.
This is the path I followed:
You open standard e.g. c++11 draft.
You seek section about classes it's section 9. You immediatietly see it has subsection "9.2 Class members". There is whole syntax defined. After some reading you get to member-declarator. The most important part in our context is declarator.
Section 8. Declarators. In p4. you have the syntax for declarator. After going through all the formal definition of the fancy syntaxes supported you will notice that it hinges on id-expression.
This is defined in 5.1.1 Primary Expressions. General ([expr.prim.general]). And it has to be a qualified-id of unqualified-id.
So your question could be rephrased to "Why does the namelookup not work like that?" But that is another question.
FWIW, not much I guess, but it's a design decision. It would need to keep track of all failed resolutions for the compilation unit. Doing lazy check in this context comes with quite far reaching implications.
After the example
class foo{
other* bar;
...
};
class other{
...
}
… which (1) uses an undeclared name, and (2) lacks a crucial semicolon, you ask
” Why isn't this possible then? (Does the standard forbids that explicitly? for what?)
The Holy Standard requires that every name must be declared before it's used.
Note that in a given C++ implementation, even data pointers can be of different sizes (void* is guaranteed to be able to hold any data pointer), not to mention function pointers.
An alternative to declare-before-first-use requirement could be to adopt a default, like with implicit int in the early C days. E.g. the compiler could assume that other was a class type. But that would not be very helpful in general, and it would complicate the language.
However, in this particular case it's possible to combine the necessary minimum declaration of other with its first use:
class foo{
class other* bar;
//...
};
class other{
//...
};
Alternatively you could use an ordinary forward declaration:
class other;
class foo{
other* bar;
//...
};
class other{
//...
};
Just so the compiler knows that other is a class type, and not e.g. a function, or a synonym for char or void (pointers to these types are the largest, if there is any variability in the size of basic raw data pointers).
You then assert:
” The dummy example I posted above may seem have no real meaning. The reason why I want to do without forward declaration is that when you got a nested class, there's no forward declaration that can preserve the encapsulation.
That's wrong.
E.g. this works nicely:
class Foo
{
private:
class Other;
Other* bar;
class Other{};
public:
Foo(): bar( new Other ) {}
};
However, the shortcut with declaration in the first use, class Other* bar;, doesn't work in this case. That's because it effectively would declare Other as a namespace level class instead of a nested one.

Will C++17 allow forward declaration of nested classes?

Not sure where to ask (feel free to close this if it is an inappropriate question) but I have not found anything on this specifically in C++17 proposals, neither this or this mentions it when dealing with the nested namespace addition to C++.
So currently this is the only option:
class A
{
public:
class B; //forward-declared INSIDE class/namespace
};
class A::B //defined outside
{
};
Will this be possible in C++17?
class A::B; //forward declared NESTED outside of parent class/namespace
class C
{
A::B *b;
};
and then either this (1) (as seems to be the proposal of nested namepsace definitions)
class A::B //definition of A::B without defining A
{
};
or this (2)
class A
{
public:
class A::B
{
};
};
or this [3]
class A
{
public:
class B;
};
class A::B
{
};
I suspect the definition of A::B without defining A first might not work though (although the proposal seems to allow it).
There's a proposal on the issue titled Forward declarations of nested classes P0289R0. However as you can see from the last Trip Report: C++ Standards Meeting in Jacksonville, February 2016, this proposal was pendent to proposals for which further work is encouraged. I'm quoting the verdict of the committee (Emphasis Mine):
This would allow things like X::A* to appear in a header without
requiring a definition for X to also appear in the header
(forward-declarations of X and X::A will be sufficient). EWG found the
use case compelling, because currently a lot of class definitions to
appear in headers only because interfaces defined in the header use
pointers or references to nested classes of the type. Several details
still need to be worked out. (For example, what happens if a
definition of X does not appear in any other translation unit (TU)?
What happens if a definition of X appears in another TU, but does not
define a nested class A? What happens if it does define a nested class
A, but it’s private? The answer to some or all of these may have to be
“ill-formed, no diagnostic required”, because diagnosing errors of
this sort would require significant linker support.)
IMHO lacking the ability to do forward deceleration of classes is a major hole in C++ language definition, which results in people using void* where a forward reference would be more safe.
Here is a workaround using namespaces:
Flatten the class structure you need to pre-declare
Use namespaces to separate the code
Do the forward deceleration using the namespaces
namespace ns1 {
namespace ns2 {
typedef class C * cptr_t; // declare both class and a pointer type
}}
ns1::ns2::C *cp; // use forward deceleration of the class
ns1::ns2::cptr_t cp; // use the typedef
This workaround does not solve the problem properly but may help in some situations.

Can friend class be declared conditionally in C++03?

I want to declare a friend class only if some (compile-time) condition is true. For example:
// pseudo-C++
class Foo {
if(some_compile_time_condition) {
friend class Bar;
}
};
I did not find any solution on the internet. I went through all the answers to the question Generating Structures dynamically at compile time. Many of them use the C++11 std::conditional, but I would like to know if it is possible to do this in C++03 without using the preprocessor.
This solution https://stackoverflow.com/a/11376710/252576 will not work because friendship is not inherited ( friend class with inheritance ).
Edit Just to make this more easily visible, as mentioned below in the comment: This requirement is unusual. This is part of a new research project in hardware simulation, that I am working on. The testbench is written in C++, and I want to display the variables in a waveform. I have researched various other options, and figured out that I need to use a friend class, due to practical considerations. The friend will capture the values and generate the waveform, but I would prefer to have the friend only when the waveform is required, and not all the time.
Use friend std::conditional<C, friendclass, void>::type; where C is your condition. A nonclass type friend will be ignored.
The conditional template is easily implemented in C++03. However since C++03 does not support typedef friends you need to use the following syntax there
namespace detail { class friendclass {}; }
class Foo {
friend class std::conditional<C,
friendclass, detail::friendclass>::type::friendclass;
};
Note that the detail dummy class name needs to match the name of the potential friend in this workaround.
[class.friend]/3 tells this :
A friend declaration that does not declare a function shall have one of the following forms:
friend elaborated-type-specifier ;
friend simple-type-specifier ;
friend typename-specifier ;
therefore it is not possible to conditionally declare friends of a class, without a macro.
It seems, unfortunately, not possible within the C++ compiler: ie, it seems that only the preprocessor may help here. Note: Johannes has a proposal, so there is hope!
However I would note that:
friendship does not require you to actually use it
friendship is a pure compile-time construct (like access specifiers) and does not incur any runtime penalty on any major compiler
there is no reason not to have unconditional friendship, but only use it if some conditions (static or dynamic) are met.
Note: in the future, this is something that the static_if proposal could cover.
Note: Johannes has pretty much nailed it. In '03 you cannot befriend
a typedef - but if you know you have a class, then you can refer to
it's injected class name.
Johannes' answer also has the benefit of using standard library functionality which too is always a good thing.
#define some_compile_time_condition 0
class Foo;
template <int Condition> class TestCondition {
private:
friend class Foo;
struct Type {
struct Bar;
};
};
template <> class TestCondition<1> {
public:
typedef Bar Type;
};
struct Bar
{
public:
void foo (Foo &);
};
class Foo {
private:
friend struct TestCondition< some_compile_time_condition >::Type::Bar;
int m_i;
};
void Bar::foo (Foo & foo)
{
foo.m_i = 0;
}
It's still different to the requirement in that Foo always has a
friend, but the befriended class changes based on the value of the
option.
An interesting side question is whether it is an ODR violation to have
versions of Foo both with and without some_compile_time_condition
set to 1.
I think you take 1 preprocessor and write your source code inside that.
bool flag = false;
#ifdef _MY_FRIEND_
friend class sample
flag = true;
#endif
if (flag)
{
...
...
...
}
class Foo {
#ifdef _MY_FRIEND_
friend class Bar;
#endif
}
};
Here _MY_FRIEND_ is a preprocessor and if you add that preprocessor then at compile time your class Bar will be the friend class...you can use that preprocssor any where when you want to need class Bar as a friend class.other wise compile without the preprocessor then it wont allow u to add Bar as a friend class of Foo
Please correct me if i understood the question wrong.

Why can't I declare a friend through a typedef?

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.