fra*_*sco 6 c++ inheritance templates using-declaration language-lawyer
对模板基类成员的访问需要语法this->member或using指令。此语法是否还会扩展到未直接继承的基本模板类?
考虑以下代码:
template <bool X>
struct A {
int x;
};
template <bool X>
struct B : public A<X> {
using A<X>::x; // OK even if this is commented out
};
template <bool X>
struct C : public B<X> {
// using B<X>::x; // OK
using A<X>::x; // Why OK?
C() { x = 1; }
};
int main()
{
C<true> a;
return 0;
}
Run Code Online (Sandbox Code Playgroud)
因为模板类的声明B包含using A<X>::x,自然衍生的模板类C可以访问x使用using B<X>::x。尽管如此,对于g ++ 8.2.1和铛++ 6.0.1上述代码编译细,其中x在访问C与using该拾取x直接从A
我本以为C无法直接访问A。此外,注释掉using A<X>::xin B仍会使代码得以编译。即使是注释掉的组合using A<X>::x中B,并在同时聘请C using B<X>::x,而不是using A<X>::x给出一个代码编译。
该代码合法吗?
加成
更明确地说:这个问题出现在模板类上,这是关于模板类继承的成员的可见性。通过标准的公有继承,公众成员A都可以访问到C,所以使用语法this->x在C一个确实可以访问A<X>::x。但是using指令呢?编译器如何正确解决using A<X>::xif A<X>不是if 的直接基础C?
您正在使用A<X>需要基类的地方。
[命名空间.udecl]
3在用作成员声明的 using 声明中,每个 using 声明符的嵌套名称说明符应命名所定义的类的基类。
由于这出现在预期类类型的位置,因此它是已知的并被假定为类型。它是一种依赖于模板参数的类型,因此不会立即查找它。
[温度分辨率]
9当查找模板定义中使用的名称声明时,通常的查找规则([basic.lookup.unqual]、[basic.lookup.argdep])用于非依赖名称。依赖于模板参数的名称查找被推迟,直到知道实际的模板参数([temp.dep])。
因此,由于编译器无法更好地了解,因此允许这样做。实例化类时,它将检查 using 声明。事实上,我们可以在那里放置任何依赖类型:
template<bool> struct D{};
template <bool X>
struct C : public B<X> {
using D<X>::x;
C() { x = 1; }
};
Run Code Online (Sandbox Code Playgroud)
X在知道的值之前不会对其进行检查。因为B<X>如果专业的话,可以带来各种惊喜。例如,可以这样做:
template<>
struct D<true> { char x; };
template<>
struct B<true> : D<true> {};
Run Code Online (Sandbox Code Playgroud)
使上述声明正确。