Why Is "Using Namespace X;" Not Allowed at Class/Struct Level

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.
}
}

Scoped using-directive within a struct/class declaration?

Given that using declarations at class scope are not inherited, this could work. The name would only be valid inside that class declaration, or inside the declarations of nested classes. But I think it's sort of overloading the concept of a class with an idea that should be larger.

In Java and Python individual files are treated in a special way. You can have import declarations that inject names from other namespaces into the file. These names will (well, not exactly with Python, but it's too complicated to explain here) only be visible within that file.

To me that argues for this sort of ability not being tied to a class declaration, but given a scope of its own instead. This would allow injected names to be used in several class declarations if it made sense, or even in function definitions.

Here is an idea I prefer because it allows these things while still giving you the benefits of a class level using declaration:

using {
// A 'using' block is a sort of way to fence names in. The only names
// that escape the confines of a using block are names that are not
// aliases for other things, not even for things that don't have names
// of their own. These are things like the declarations for new
// classes, enums, structs, global functions or global variables.
// New, non-alias names will be treated as if they were declared in
// the scope in which the 'using' block appeared.

using namespace ::std;
using ::mynamespace::mytype_t;
namespace mn = ::mynamespace;
using ::mynamespace::myfunc;

class AClass {
public:
AClass(const string &st, mytype_t me) : st_(st), me_(me) {
myfunc(&me_);
}

private:
const string st_;
mn::mytype_t me_;
};
// The effects of all typedefs, using declarations, and namespace
// aliases that were introduced at the level of this block go away
// here. typedefs and using declarations inside of nested classes
// or namespace declarations do not go away.
} // end using.

// Legal because AClass is treated as having been declared in this
// scope.
AClass a("Fred", ::mynamespace::mytype_t(5));

// Not legal, alias mn no longer exists.
AClass b("Fred", mn::mytype_t);

// Not legal, the unqualified name myfunc no longer exists.
AClass c("Fred", myfunc(::mynamespace::mytype_t(5));

This is analogous to declaring a block for local variables in a function. But in this case you are declaring a very limited scope in which you will be changing the name lookup rules.

Constant in separate namespace using class/struct with a big constuctor

I suggest a constexpr init method if you can't make the whole constructor constexpr containing all the code that should be duplicated. Note that if a function is constexpr you can call it even if in that case a non constexpr would work too.

 constexpr void init(...){
//a lot of stuff
}
ColorspaceData(...){
init(...)
//not constexpr stuff
}
constexpr ColorspaceData(...){
init(...)
//constexpr stuff
}

Why is using namespace std; considered bad practice?

Consider two libraries called Foo and Bar:

using namespace foo;
using namespace bar;

Everything works fine, and you can call Blah() from Foo and Quux() from Bar without problems. But one day you upgrade to a new version of Foo 2.0, which now offers a function called Quux(). Now you've got a conflict: Both Foo 2.0 and Bar import Quux() into your global namespace. This is going to take some effort to fix, especially if the function parameters happen to match.

If you had used foo::Blah() and bar::Quux(), then the introduction of foo::Quux() would have been a non-event.

In what scopes is the using namespace clause valid?

From cppreference.com:

Using-directives are allowed only in namespace scope and in block scope.

So you can use them within a namespace (including the global namespace) or within a code block. A class declaration is neither of those.

inheritance just to share enum - dangerous?

It's not "dangerous" per-se. It's just bad design.

Class inheritance is supposed to define an IS-A relationship.

When inheriting from something that isn't "natural", you tend to get problems later along the development road.

Some of this design implications that could affect you are:

1. Multiple inheritance of the same class in a deeper inheritance graph.

2. Pointer casts may be affected if you change the inheritance structure in the future (Which is something you don't want to happen just for a convenience inheritance)

A couple of better solutions:

1. Contain the enums in a namespace - use #using namespace. Adding that in the header will propagate to any compilation unit that includes that header.

2. In C++11 you can just use enum classes - Not in inheritance, but it gives you stronger type safety.



Related Topics



Leave a reply



Submit