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.
Related
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.
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.
This question already has answers here:
When can I use a forward declaration?
(13 answers)
Closed 8 years ago.
I'm analying an Operating Systems project for school and came across this header file:
//kernelev.h
#ifndef _KERNELEV_H
#define _EVENT_H_
typedef unsigned char IVTNo;
class Thread;
class PCB;
class KernelSem;
class KernelEv {
public:
KernelEv (IVTNo ivtNo);
~KernelEv();
int wait(int MaxTimeToWait);
void signal();
[...]
Now, when writing the complete definitions of these methods (KernelEv, ~KernelEv, wait and signal), they used the attributes of the classes Thread, PCB and KernelSem. What would be the difference between generally introducing for instance #include Thread.h; #include KernelSem.h; and just declaring the classes like this: class Thread; Are there differences in data access rights? Or it's somehow completely different?
Thanks for your help, I hope my question is clear enough.
First, note that if you only introduce the classes, you won't be able to use the methods;
class Thread;
Thread x; // compile error: size of x unknown
Thread* x; // this is ok
// set x to some valid thread, maybe as a parameter
x->signal(); // compile error
But it makes no difference whether your declarations are in a header or included in your file. That is, you could replace the include line with a copy of the header and everything would work perfectly fine (every line in the above example would be valid). There are many reasons not to, however. Ease of maintenance would be the top issue, along with readability and modularity. It would also be less applicable to compiler caching (so would generally take longer to compile)
If you only have a declaration class A; and not the full class definition, then the type is said to be incomplete. This can be used in limited ways; you can do things that only need knowledge that the class exists, for example:
Declare a pointer or reference to it;
Declare a function using it as a parameter or return type;
Declare (but not define) an external variable of that type.
You can't do anything that requires knowledge of the class members, size, or other details given by the definition, for example:
Define a variable of that type;
Define a function using it;
Access any members or nested declarations;
Inherit from it;
Apply sizeof to it.
If I am not wrong, you are asking about Declaration vs Definition. They are different but related.
I forward you to this two posts googled as "c++ declaration definition", since they will explain much better than me :)
What is the difference between a definition and a declaration?
http://www.cprogramming.com/declare_vs_define.html
Just comment that your class A; is a declaration, while the includes Thread.h surely will have plenty definitions inside (and maybe declarations too).
--------------------- edit:
About forward declarations as commented by #Dave bellow:
class B ; // needed declaration
class A {
B field ;
} ;
class B {
A field ;
};
I came across the following code in an article
struct entire_program
{
struct B;
struct A
{
B *bbb;
void Aa() { B bb; bb.Bb(); };
};
struct B
{
A aaa;
void Bb() { A aa; aa.Aa(); };
};
};
Why am I allowed to call method Bb() in this case, but if I change struct entire_program to namespace entire_program it generates a compiler error?
I already read this question, what I am asking is: if it is possible to call methods that are undefined yet within classes/structs/unions why don't namespaces work the same way? I am interested in the motivation behind this behavior.
Related question on Programmers.SE (for those interested in the coding style presented in the article)
This is just the way classes and namespaces work in C++. Classes have to bring the entire set of (class member) names as candidates because otherwise you'd have a huge burden of ordering your class members and might not conveniently be able to order your public interface first, for example.
Namespaces on the other hand work almost exactly like C functions and are processed sequentially in the order they're listed in the source file. Special features aren't needed since you can always declare your function before calling it at namespace/global scope.
Circular dependency is possible inside both classes and namespaces. It is just a matter of defining things correctly in circular dependency situations.
In your case the code compiled with struct entire_program because of special treatment in-class member function definitions: they are allowed to "see" the entire definition of the enclosing class(es), both above and below the current point. But they cannot see the entire definition of the enclosing namespace. With namespaces the compiler only sees what has been declared above the current point.
Classes and namespaces are very different things, so the problem of switching freely between the two does not usually arise in practice. But just for illustrative purposes this can be achieved in many cases, including your artificial example
namespace entire_program
{
struct B;
struct A
{
B *bbb;
void Aa();
};
struct B
{
A aaa;
void Bb() { A aa; aa.Aa(); }
};
}
inline void entire_program::A::Aa()
{
B bb; bb.Bb();
}
My implementation above has the same effect as yours, but it does not rely on that special treatment of member functions. You can freely switch between struct entire_program and namespace entire_program, if you so desire. Just remember that namespace definition does not have a ; after the closing }.
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.