When I write A::B::C, with A being a class, and B being its base class, I assume I'm accessing C which is defined in that base B. This wouldn't work when B isn't actually a base of A. However, the same apparently isn't true when B is a template, e.g. A::B<123>::C still gives me B<123>::C, and it doesn't seem to matter whether B<123> is actually a base of A or not. I'm at a loss why there could be a difference. Does it not interpret A::B<123> as accessing base class B<123> of class A? Why not? Can it be rewritten somehow so it does interpret it like accessing a base class?
Here's a snippet explaining what's done in detail, with comments explaining every step:
// Here we show that we can't access a non-existent base of A
namespace WorksAsExpectedWithoutTemplates {
struct B
{
using C = void;
};
struct D
{
using C = void;
};
struct A: B
{
};
// Compiles as expected, B is a base of A, so Foo is B::C, aka void
using Foo = A::B::C;
// Doesn't compile, as expected, because D isn't a base of A, even though D::C
// exists
using Bar = A::D::C; // WE DON'T EXPECT THIS TO COMPILE, WHICH IS FINE
}
// Now we try the same thing with templates, and it doesn't behave the same way.
// Why?
namespace ActsDifferentlyWithTemplates {
template< int >
struct B
{
using C = void;
};
struct A: B< 42 >
{
};
// Compiles as expected, B< 42 > is a base of A, so Foo is B< 42 >::C, aka void
using Foo = A::B< 42 >::C;
// Compiles, Bar is B< 123 >::C, even though B< 123 > is not a base of A. Why
// does this behave differently than in the non-template case above? Can this be
// rewritten differently so that this wouldn't compile, same as in
// WorksAsExpectedWithoutTemplates, since B< 123 > isn't a base of A?
using Bar = A::B< 123 >::C; // WHY DOES THIS COMPILE? B< 123 > isn't a base of A
}
A::B<123>::Cis interpreted asA::template B<123>::C.