当它是模板时访问基础 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>::C
,B<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 >::C
与 B< 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。
当我写 A::B::C
时,A
是 class,B
是它的基础 class,我假设我正在访问 C
是在那个基数 B
中定义的。当 B
实际上不是 A
的基数时,这将不起作用。但是,当 B
是模板时,情况显然不一样,例如A::B<123>::C
仍然给我 B<123>::C
,B<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 >::C
与 B< 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。