Why Can't I Forward-Declare a Class in a Namespace Using Double Colons

Why can't I forward-declare a class in a namespace using double colons?

Because you can't. In C++ language fully-qualified names are only used to refer to existing (i.e. previously declared) entities. They can't be used to introduce new entities.

And you are in fact "reopening" the namespace to declare new entities. If the class Class is later defined as a member of different namespace - it is a completely different class that has nothing to do with the one you declared here.

Once you get to the point of defining the pre-declared class, you don't need to "reopen" the namespace again. You can define it in the global namespace (or any namespace enclosing your Namespace) as

class Namespace::Class {
/* whatever */
};

Since you are referring to an entity that has already been declared in namespace Namespace, you can use qualified name Namespace::Class.

Forward declaring classes in namespaces

Seems as though the answer lies in the C++ specification:

3.3.5 "Namespace scope" in the standard.

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.

A namespace member can also be
referred to after the :: scope
resolution operator (5.1) applied to
the name of its namespace or the name
of a namespace which nominates the
member’s namespace in a
using-directive;

How to forward declare a class which is in a namespace

To forward declare class type a in a namespace ns1:

namespace ns1
{
class a;
}

To forward declare a type in multiple level of namespaces:

namespace ns1
{
namespace ns2
{
//....
namespace nsN
{
class a;
}
//....
}
}

Your are using a a member of consumer which means it needs concrete type, your forward declaration won't work for this case.

Name conflict in forward declaration

In file.hpp, the forward declaration should be:

namespace System {
namespace Sysutils {
class TMultiReadExclusiveWriteSynchronizer;
}
}

And probably all references to the type (at least in the header file) should have the
fully qualified name System::Sysutils::TMultiReadExclusiveWriteSynchronizer.

How to deal with namespaces in forward declarations?

Forward-declare the class in the namespace:

namespace SomeNamespace
{
class ForwardDeclaredClass;
}

Reason for not allowing forward declarations of nested class?

The reason that it is not in the language is simply that nobody has come up with a good proposal on how to include it in the language. Features don't include themselves, someone has to write it up and explain the advantages and that there are no (or very minor) disadvantages.

The argument for not forward declaring enums (enum x;) was simply that the compiler cannot select the proper size for enum variables until it has seen how many values there are. This problem was solved by allowing you to decide for the compiler (enum x : int;). This has also been implemented and shown to work properly, before entering the standard.

See http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf

forward declaration of a class template including a namespace causes compile-error

Yes, this is a bug.

According to [dcl.type.elab]/1,

... If an elaborated-type-specifier is the sole constituent of a declaration, the declaration is ill-formed unless it is an explicit specialization, an explicit instantiation or it has one of the following forms:

  • class-key attribute-specifier-seqopt identifier ;
  • friend class-key ::opt identifier ;
  • friend class-key ::opt simple-template-id ;
  • friend class-key nested-name-specifier identifier ;
  • friend class-key nested-name-specifier templateopt simple-template-id ;

your declaration class N1::Other is neither an explicit specialization, nor an explicit instantiation, so it has to have the emphasized form (ignoring those friend declaration). Note no nested-name-specifier is allowed before identifier in the emphasized form, so the declaration is ill-formed. The compiler error of Clang in the following example without template shows this problem.

namespace N {
struct S;
}
struct N::S; // error: forward declaration of struct cannot have a nested name specifier

LIVE EXAMPLE (BTW, GCC accepts this code and just gives a warning about nothing new to be declared. I guess it is a bug of GCC.)

Here the template-head template <typename> does not help, because class N1::Other itself should form a declaration according to the grammar definition of template-head, thus the paragragh above applies.

Roughly speaking, a declaration for class in different scope from the scope where a class with the same name is declared should either introduce a new class, in which case nested-name-specifier should not be used, or define the previously declared class, in which case the grammar forms a class-specifier rather than an elaborated-type-specifier, thus the paragraph above does not apply. As a conclusion, this rule is reasonable.

Why can't forward declared friend class be referred in the class?

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.



Related Topics



Leave a reply



Submit