模板化继承中的范围解析(可能称为mixin)

use*_*486 6 c++ templates scope-resolution

假设我有模板化的类

#include <iostream>

class A1 {
public:
  int x{314159};
};

template<typename Context>
class A2 : public Context {};

template<typename Context>
class A3 : public Context {};

template<typename Context>
class A4 : public Context {
public:
  int func() {
    return Context::A1::x;
  }

  int gunc() {
    return this->A1::x;
  }

  int hunc() {
    return A1::x;
  }
};

int main() {
  A4<A3<A2<A1>>> my_A;

  std::cout << "x = func() = " << my_A.func() << std::endl;
  std::cout << "x = gunc() = " << my_A.gunc() << std::endl;
  std::cout << "x = hunc() = " << my_A.hunc() << std::endl;

  return 0;
}
Run Code Online (Sandbox Code Playgroud)

在模板化类的定义内部A4,至少当仅使用实例类型时A4<A3<A2<A1>>>,似乎可以将其x称为

this->A1::x;
Run Code Online (Sandbox Code Playgroud)

要么

Context::A1::x;
Run Code Online (Sandbox Code Playgroud)

要么

A1::x;
Run Code Online (Sandbox Code Playgroud)

问题1:这些是否相等?好吧,我认为从A4孤立地查看模板化类的角度来看,它们并不等效。为了Context::A1::x正常工作,其模板参数应包含x。为了this->A1::x起作用,它应该包含一个称为的范围A1,而该范围又应包含一个x。而对于A1::x工作的范围A4本身就应该包含一个名为范围A1包含x我的目的是从类型的角度询问它们是否等效 A4<A3<A2<A1>>>

注意: gcc 8.2 -O03 -std=c++17在每种情况下都会产生相同的汇编代码。也就是说,我仅使用函数funcgunchunc以及对相应函数的一个调用来编译代码,并且此编译器生成了相同的可执行文件。当然,严格来说,这不一定意味着对于抽象语言而言,这些表达是等效的。

问题2:x在每种情况下如何“展开”工作范围?也许这个问题没有道理,或者不完全是我要问的问题。特别是如果对问题1的回答是等同的。在找到有关问题1的更多信息之后,请允许我修改此问题,或者先忽略此问题。

对问题2的注释:此观察结果可以阐明为什么我不确定拆包的工作方式。如果在模板化类中A4我们还有一个方法

int iunc() {
  return Context::Context::A1::x;
}
Run Code Online (Sandbox Code Playgroud)

然后编译失败

memberTemplatedParent.cpp: In instantiation of ‘int A4<Context>::iunc() [with Context = A3<A2<A1> >]’:
memberTemplatedParent.cpp:48:45:   required from here
memberTemplatedParent.cpp:37:22: error: no type named ‘Context’ in ‘class A3<A2<A1> >’
 return Context::Context::A1::x;
                  ^
Run Code Online (Sandbox Code Playgroud)

因此,至少gccA4创建的类型实例时,其模板参数的template参数不是有效名称(或者我在中未正确命名Context::Context::A1::x)。

Han*_*999 1

问题1和2:

对于您选择的实例化,所有版本都是等效的。只要不歧义,就可以x直接使用该成员,而无需指定范围。如果该成员不在当前类中,则检查基类,依此类推。

如果您指定特定的基类并且该成员x不存在,则将再次查询该基类。

对于您的特定专业,您有

class A2<A1> : public A1 {};

class A3<A2<A1>> : public A2<A1>{};

class A4<A3<A2<A1>>> : public A3<A2<A1>> {
public:
  int func() {
    return A3<A2<A1>>::A1::x;  // fine: search for x in A1,
                               // where A1 is searched in A3<A2<A1>>
  }
  int gunc() {
     return this->A1::x; // fine: why not specifying A1 directly. The this pointer
                         // is not required here but adding does not cause any harm.
  }
  int hunc() {
     return A1::x; // fine: why not specifying A1 directly.
  }
  int iunc() {
     return x; // fine: would be possible as well
  }
Run Code Online (Sandbox Code Playgroud)

};

最后一个问题:

int iunc() {
  return Context::Context::A1::x;
}
Run Code Online (Sandbox Code Playgroud)

模板实例化后内容如下

int iunc() {
  return A3<A2<A1>>::Context::A1::x;
}
Run Code Online (Sandbox Code Playgroud)

A3<A2<A1>>编译器现在抱怨引入 name 的类中没有 typedef Context。模板参数仅在类模板内可见。