Scoped Using-Directive Within a Struct/Class Declaration

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.

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

friend class declaration and using directive

While using namespace N is pulling the name N::A into the global namespace, it is not declaring that A in the global namespace. Hence an additional A in the global namespace is the friend of B. clang is wrong.

Hiding names with 'using' directive

It seems that it is a bug of gcc. According to the C++ 20 Standard (6.3.7 Class scope)

2 A name N used in a class S shall refer to the same declaration in
its context and when re-evaluated in the completed scope of S. No
diagnostic is required for a violation of this rule.

In this case

struct A {};
struct B { using A = A; };

the name B::A refers to the same declaration of struct A.

Here is an example from the C++ Standard that shows the meaning of the quote.

typedef char* T;
struct Y {
T a; // error: T refers to ::T but when reevaluated is Y::T
typedef long T;
T b;
};

Why can't I put a using declaration inside a class declaration?

Could you do typedef gee::whiz::abc::def::Hello Hello?

Using directive fails within template

It doesn't work because C++ language has no such feature and never had. A using-declaration for a class member must be a member declaration. This means that you can only use in class scope, but never in local scope. This all has absolutely nothing to do with templates.

In other words, you can place your using-declaration into class scope

struct Derived : public Base<T> {
...
using Base<T>::x;
...
};

but you can't have it inside a function.

Using-declarations for namespace members can be placed in local scope, but using-declarations for class members cannot be. This is why the error message complains about Base<T> not being a namespace.



Related Topics



Leave a reply



Submit