Why Can't We Declare a Namespace Within a Class

Why can't we declare a namespace within a class?

There's no real advantage to adding such a feature to the language. Features generally don't get added unless there's demand.

What would namespaces inside classes buy you? Would you really rather say binary_tree::iterator::left_depth instead of simply binary_tree::left_depth? Perhaps if you had multiple namespaces inside, you use them to distinguish say binary_tree::depth_iterator::left and binary_tree::breadth_iterator::right.

In any event, you can achieve the desired result using internal classes as a poor-programmer's namespace, which is even more reason why there isn't demand for true namespaces inside classes.

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.

Why can't we declare namespace aliases inside a class?

I'm not an expert on the C++ Standard but I'll stick my neck out and have a go at answering your question. I assume the use of namespace N = A within a class declaration falls foul of the definition of how a class member should be defined.

The C++ Standard defines a class member as

member-specification:
member-declaration member-specification_opt
access-specifier : member-specification_opt
member-declaration:
decl-specifier-seq_opt member-declarator-list_opt ;
function-definition ;opt
::opt nested-name-specifier templateopt unqualified-id ;
using-declaration
static_assert-declaration
template-declaration
member-declarator-list:
member-declarator
member-declarator-list , member-declarator
member-declarator:
declarator pure-specifier_opt
declarator constant-initializer_opt
identifier_opt : constant-expression
pure-specifier:
= 0
constant-initializer:
= constant-expression

The important point being the = in the declaration, the compiler is expecting either a pure-specifier or constant-initializer statement and as the line does not end in a zero, we are not applying a pure-specifier in this case.

Analysing the namespace N = A declaration the compiler sees this as

declarator = constant-expression

And since namespace is a keyword it cannot be used.

typedef is permitted because (from the standard)

Nested types are classes and enumerations defined in the class,
and arbitrary types declared as members by use of a typedef declaration.

Why is using namespace X; not allowed at class/struct level?

I don't know exactly, but my guess is that allowing this at class scope could cause confusion:

namespace Hello
{
typedef int World;
}

class Blah
{
using namespace Hello;
public:
World DoSomething();
}

//Should this be just World or Hello::World ?
World Blah::DoSomething()
{
//Is the using namespace valid in here?
}

Since there is no obvious way of doing this, the standard just says you can't.

Now, the reason this is less confusing when we're talking namespace scopes:

namespace Hello
{
typedef int World;
}

namespace Other
{
using namespace Hello;
World DoSomething();
}

//We are outside of any namespace, so we have to fully qualify everything. Therefore either of these are correct:

//Hello was imported into Other, so everything that was in Hello is also in Other. Therefore this is okay:
Other::World Other::DoSomething()
{
//We're outside of a namespace; obviously the using namespace doesn't apply here.
//EDIT: Apparently I was wrong about that... see comments.
}

//The original type was Hello::World, so this is okay too.
Hello::World Other::DoSomething()
{
//Ditto
}

namespace Other
{
//namespace Hello has been imported into Other, and we are inside Other, so therefore we never need to qualify anything from Hello.
//Therefore this is unambiguiously right
World DoSomething()
{
//We're inside the namespace, obviously the using namespace does apply here.
}
}

May I declare using namespace inside a C++ class?

using namespace X; is called a using directive and it can appear only in namespace and function scope, but not class scope. So what you're trying to do is not possible in C++. The best you could do is write the using directive in the scope of the namespace of that class, which may not be desirable.

On second thought, though, analyzing your words,

Assume having a C++ class. And there's a namespace which should be
visible only inside my class. What to do for that?

I'd suggest something like the following, which I am not sure is what you want.

class A
{
public:
void Method1();
void Method2();
void Method3();

private:

class B
{
//public static functions here, instead of namespace-scope
// freestanding functions.
//these functions will be accessible from class A(and its friends, if any)
//because B is private to A
};

};

Defining a class within a namespace

You're close, you can forward declare the class in the namespace and then define it outside if you want:

namespace ns {
class A; // just tell the compiler to expect a class def
}

class ns::A {
// define here
};

What you cannot do is define the class in the namespace without members and then define the class again outside of the namespace. That violates the One Definition Rule (or somesuch nonsense).

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.



Related Topics



Leave a reply



Submit