1

I bring here 3 versions of code, the first one causes a compilation error, the second and the third were compiled successfully.


Code 1:

I created class Bottom is a nested class in Middle which is a nested class in a template class Top

template <class>
struct Top {
    struct Middle {
        struct Bottom {};
    };
    void useclass(Middle::Bottom);
};

This code gives an error:

main.cpp:6:27: error: 'Top::Middle::Bottom' is not a type
 void useclass(Middle::Bottom);
                       ^

Code 2:

Similar to Code 1 but with Top is a normal class (non-template)

struct Top {
    struct Middle {
        struct Bottom {};
    };
    void useclass(Middle::Bottom);
};

This code was compiled successfully without any errors

Code 3:

Similar to Code 1 but with method useclass taking Middle instead of Bottom

template <class>
struct Top {
    struct Middle {
        struct Bottom {};
    };
    void useclass(Middle);
};

This code was compiled successfully as well


Please tell me:

  • Why Code 1 can't be compiled, which rule of C++ prevents it from being compiled?

  • Is there any way to use a nested class in a nested class in a template class like Bottom as a type?

DMaster
  • 603
  • 1
  • 10
  • 23
  • @PeteBecker I updated, thank you! – DMaster May 03 '16 at 11:13
  • @M.M Not even that. It is a dupe of http://stackoverflow.com/questions/610245/where-and-why-do-i-have-to-put-the-template-and-typename-keywords – NathanOliver May 03 '16 at 11:46
  • @NathanOliver which part of that code explains OP's situation exactly? It's not clear to me – M.M May 03 '16 at 11:48
  • @M.M Doesn't *The "typename" keyword The answer is: We decide how the compiler should parse this. If t::x is a dependent name, then we need to prefix it by typename to tell the compiler to parse it in a certain way.* and the preceding information make that clear? – NathanOliver May 03 '16 at 11:49
  • No. Why is Middle::Bottom dependent and not Middle? They're both in Top. How can `useclass(Middle::Bottom)` be parsed wrong? – M.M May 03 '16 at 11:52
  • @M.M I did figured it out, and I updated it, but the update doesn't answers the question completely: I hadn't pointed out *which rule of C++*. So, I didn't placed it in the answer box. – DMaster May 03 '16 at 12:22
  • @DMaster it's still an answer even if it's lacking in explanation compared to other possible answers (which haven't been posted) – M.M May 03 '16 at 12:27
  • @M.M Because you can explicitly specialize `Middle` later? – T.C. May 03 '16 at 22:09
  • @T.C. I tried that but it gives an error that explicit specialization may not follow instantiation (`void useclass(typename Middle::Bottom)` apparently causes instantiation) – M.M May 04 '16 at 00:12
  • @M.M Right, because instantiates the class instantiates the declaration which instantiates `Middle`, but if you have something using `Middle::Bottom` in the body rather the signature then the explicit specialization will go through. – T.C. May 04 '16 at 00:14

1 Answers1

2

I just firgured it out, I need to place typename before Middle::Bottom in Code 1 and it would be compiled successfully.

template <class>
struct Top {
    struct Middle {
        struct Bottom {};
    };
    void useclass(typename Middle::Bottom);
};

P.S. I still expect some answers with more details, e.g. Why compiler doesn't recognize Middle::Bottom as a type without a keyword typename?

DMaster
  • 603
  • 1
  • 10
  • 23