基本模板类的成员的可见性未直接继承

fra*_*sco 6 c++ inheritance templates using-declaration language-lawyer

对模板基类成员的访问需要语法this->memberusing指令。此语法是否还会扩展到未直接继承的基本模板类?

考虑以下代码:

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在访问Cusing该拾取x直接从A

我本以为C无法直接访问A。此外,注释掉using A<X>::xin B仍会使代码得以编译。即使是注释掉的组合using A<X>::xB,并在同时聘请C using B<X>::x,而不是using A<X>::x给出一个代码编译。

该代码合法吗?

加成

更明确地说:这个问题出现在模板类上,这是关于模板类继承的成员的可见性。通过标准的公有继承,公众成员A都可以访问到C,所以使用语法this->xC一个确实可以访问A<X>::x。但是using指令呢?编译器如何正确解决using A<X>::xif A<X>不是if 的直接基础C

Sto*_*ica 4

您正在使用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)

使上述声明正确。