Qualified name of a local class

Viewed 182

typename keyword in a declaration requires a qualified type name after it (a type name with a nested name spacifier in front of it). But what is a qualified name of a local class or struct? Here is the example:

struct A{};
namespace bb { struct B{}; }
int main()
{
    struct C{};

    typename A a; // not OK, because A is not a qualified typename
    typename ::A a; // OK, because it contains a nested name specifier
    typename B b; // not OK, because B is not a qualified typename
    typename bb::B b; // OK, because it contains a nested name specifier
    typename C c; // not OK in gcc and clang but compiles in Visual Studio
}

This is the error I get from clang: expected a qualified name after 'typename'

This is the error reported by gcc: <source>:21:14: error: expected nested-name-specifier before 'C'

Is it possible to use a local class name after typename? If so then what is the qualified name of it? The class is reported as main()::C in clang error messages, but that obviously is not its qualified name. I couldn't find a place in the C++ standard that forbids using local classes in this context. Am I missing something? Visual Studio is not complaining about typename C c; so is it a bug in gcc and clang?

PS. I know I can declare variables without typename in front of them if I don't use templates, but I am just curious if this is a bug in the language, a bug in gcc/clang or Visual Studio, or I am missing something.

2 Answers

Sounds like gcc and clang are stricter and correct, while VS is more permissive (not sure if it qualifies as a bug).

As you've correctly written already, typename requires a qualified name. That is "a name that appears on the right hand side of the scope resolution operator ::". There is no way of using :: with local class, which means that there is no ::-qualified name for one (so, as in the definition quoted above). Whether such requirement has a good logic or not, posterity will probably decide, but for what is worth, the following does work:

int main()
{
    struct C { public: struct D{}; };

    typename C::D d; // ok

    return 0;
}

Also probably worth mentioning, using typename outside a template was permitted starting with c++11, in case older compilers are used.

Nice experiment. I never thought about to instantiate structs using typename. I created addtional code and was wondering that it worked:

struct C{
    int c = 1;
};
void foo(){
    struct C{
        int c = 0;
    };

    typename ::C c;
    C c_;
    std::cout << "c.c: " << c.c << std::endl; //c.c: 1
    std::cout << "c_.c: " << c_.c << std::endl; //c_.c: 0

    return;
}

int main()
{
    foo();
}

I guess the reason why typename C c; does not work, is that there exists no linkage for structs defined within functions. The keyword typename indicates that a type is following. But the compiler/linker is not able to find it.

Please let me know if my assumption is correct or wrong. Thanks in advance!

Related