Are "using typename" directives not implemented by compilers?
Asked Answered
P

2

7

I have some code which looks like this:

namespace myLibrary
{
    class A
    {
    public:
        struct Nested
        {
            ...
        };

        ...
    };
}

In some other parts of the code, I need to access A. Since I like readable code, I also like the using directive:

using myLibrary::A;
...
A a;

Now, at some point I also need to access my nested class, so I want to write something like this:

using myLibrary::A::Nested;

Obviously, the compiler can't know that this is a nested class and not a class member, and gives me an error:

error : using declaration can not refer to class member

What I can't understand is why this does not solve the problem:

using typename myLibrary::A::Nested;

The compiler still gives me the exact same error!

Luckily, I have alternatives:

// Using a typedef
typedef myLibrary::A::Nested Nested;

// Using the new C++11 syntax for type aliasing
using Nested = myLibrary::A::Nested;

but I'd like to understand why the using typename directive did not work. Does it not do what I think it does? Or is it not implemented by compilers? If it is the latter, is there a reason for it?

Preposterous answered 24/5, 2014 at 17:22 Comment(8)
As far as I can tell, it's only intended for namespace members, not class members: en.cppreference.com/w/cpp/keyword/usingViolent
@DiscoStu: maybe, but in this case why introduce the "typename" keyword? It seems to be supposed to work with using: en.cppreference.com/w/cpp/language/using_declarationPreposterous
What is the context in which you're trying to use the using-declaration?Monteith
@dyp: no special context, I use them like I'd use a typedef. Namely, on top of a .cpp file, juste after the #include directivesPreposterous
Hmm.. These kind of using-directives can be used inside classes to refer to members of base classes (make them visible). Not sure why they're illegal outside of classes, even when they refer to types.Monteith
Nested must always be referred to as A::Nested unless it's in member variables or functions of A. If your code seems to call for talking about Nested without A:: , that's a sign that it might be a better design not to have it as a nested class.Console
@MattMcNabb Well so what about the typedef? That's almost the same as a using-declaration, just more boilerplate. IMO, it leads to the question why isn't it allowed to use a using-declaration naming a nested type outside a derived class?Monteith
@MattMcNabb: if you want to know, A is a class describing a robotic joint and Nested is a struct of the angular limitations of the joint. It makes sense to me to have it nested, even though I sometime have to access it from the outside.Preposterous
B
3

A using declaration referring to a namespace member A may only appear at namespace or local scope.

A using declaration referring to a class member Nested may only appear at class scope (along with member declarations), in a class derived from Nested. In fact, such using declarations are grammatically considered to be member declarations. They are used to adjust access qualification, and (with typename) to allow members of type-dependent bases to be used without qualification. These are specific use cases, so member using declarations are a bit specialized.

A nested class is a member of its enclosing class. You should generally avoid using class enclosures as a substitute for namespaces. Metaprogramming provides some exceptions to the rule, but in those cases you still wouldn't use using declarations, at least at namespace scope, because namespaces cannot be templated. Inheriting from an empty metaprogramming class is viable, but do mind the spaghetti.

The using directive is a different beast. It looks like using namespace and it links one namespace to another as a fallback path in name lookup.

Bloodroot answered 25/5, 2014 at 3:11 Comment(0)
E
4

There is no "using typename directive". There are using-directives and using-declarations.

You're not using any using-directives, and they aren't relevant to the question in any case (they name namespaces, and can't use the typename keyword).

When using-declarations happen to appear within class templates, and happen to name dependent types, they have to use the typename keyword just like anything else that happens to be in a template and happens to name a dependent type.

For example:

template <typename A, typename R>
class Functor : public std::unary_function<A, R>
{
    using typename std::unary_function<A, R>::result_type;
    using typename std::unary_function<A, R>::argument_type;
 public:
    result_type operator() (argument_type) {}
};

In your situations, the namespace-declaration does not appear to be a part of the body of a class template, in fact it appears to be at namespace scope, in which case attempting to name a class member (doesn't matter if it's a type or a function or whatever) violates 7.3.3[namespace.udecl]/8

A using-declaration for a class member shall be a member-declaration

as the compiler correctly diagnosed with "error : using declaration can not refer to class member"

Exemplary answered 25/5, 2014 at 2:8 Comment(1)
Thanks a lot! Sorry for calling it a "directive". I thought that the difference was that the "using declarations" were those in the body of a class and the "using directives" the others.Preposterous
B
3

A using declaration referring to a namespace member A may only appear at namespace or local scope.

A using declaration referring to a class member Nested may only appear at class scope (along with member declarations), in a class derived from Nested. In fact, such using declarations are grammatically considered to be member declarations. They are used to adjust access qualification, and (with typename) to allow members of type-dependent bases to be used without qualification. These are specific use cases, so member using declarations are a bit specialized.

A nested class is a member of its enclosing class. You should generally avoid using class enclosures as a substitute for namespaces. Metaprogramming provides some exceptions to the rule, but in those cases you still wouldn't use using declarations, at least at namespace scope, because namespaces cannot be templated. Inheriting from an empty metaprogramming class is viable, but do mind the spaghetti.

The using directive is a different beast. It looks like using namespace and it links one namespace to another as a fallback path in name lookup.

Bloodroot answered 25/5, 2014 at 3:11 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.