当它是模板时访问基础 class 时的不同行为

Different behavior when accessing a base class when it's a template

当我写 A::B::C 时,A 是 class,B 是它的基础 class,我假设我正在访问 C 是在那个基数 B 中定义的。当 B 实际上不是 A 的基数时,这将不起作用。但是,当 B 是模板时,情况显然不一样,例如A::B<123>::C 仍然给我 B<123>::CB<123> 是否实际上是 A 的基数似乎并不重要。我不知道为什么会有所不同。它不会将 A::B<123> 解释为访问 class A 的基 class B<123> 吗?为什么不?能否以某种方式重写它,使其像访问基数一样解释它 class?

这里有一个片段详细解释了所做的事情,并附有解释每一步的注释:

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

template< int > struct B 有一个 injected-class-name B 作为模板名称,如果它紧跟在 < 之前。 class struct A 继承了这个。

因此,A::B< 123 >::CB< 123 >::C 相同,而不是基础 class B< 42 >。例如:

template<int X>
struct B {
    using C = char[X];
};

struct A : B<42> {};

using Foo = A::B<42>::C;
using Bar = A::B<123>::C;
using Baz = A::B::C;  // (injected-class-name without template)

static_assert(sizeof(Foo) == 42);
static_assert(sizeof(Bar) == 123);  // This is a different type
static_assert(sizeof(Baz) == 42);

None 这些案例实际上是“访问一个基地 class”。它们都像任何其他成员类型别名/成员模板一样从基础 class 继承 injected-class-name。