假设我有模板化的类
#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;
}
在模板化类A4
的定义中,至少在仅使用实例类型A4<A3<A2<A1>>>
的情况下,似乎可以将x
称为两者之一
this->A1::x;
或
Context::A1::x;
或
A1::x;
问题1:这些等效吗?好吧,我认为从单独查看的模板化类A4
的角度来看,我认为它们并不等效。为了使Context::A1::x
工作,其模板参数应包含x
。为了使this->A1::x
工作,它应该包含一个名为A1
的范围,而该范围又应包含一个x
。为了使A1::x
工作,A4
本身的范围应包含一个名为A1
的范围,其中包含一个x
。 我的目的是从类型的角度询问它们是否等效 A4<A3<A2<A1>>>
。
Nota bene:带有-O03 -std=c++17
的gcc 8.2在每种情况下都会产生相同的汇编代码。即,我仅使用函数func
,gunc
和hunc
中的一个编译了代码,并且仅对相应的一个调用进行了编译,并且此编译器生成了相同的可执行文件。当然,严格来说,这不一定意味着对于抽象语言而言,这些表达是等效的。
问题2:在每种情况下,x
范围的“拆包”如何工作?也许这个问题没有道理,或者不完全是我要问的问题。特别是如果对问题1的回答是等同的。在找到有关问题1的更多信息之后,请允许我修改此问题,或者先忽略此问题。
问题2:的注意事项可能会阐明为什么我不确定拆包的工作方式。如果在模板化类A4
中,我们还有一个方法
int iunc() {
return Context::Context::A1::x;
}
然后编译失败并显示
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;
^
因此,至少对于创建gcc
的类型实例的A4
而言,其template参数的template参数不是有效名称(或者我没有为其命名)正确地放在Context::Context::A1::x
中。
答案 0 :(得分:2)
在这种情况下,我认为您正在继承(使用模板)。因此,Context :: x引用了父对象的x属性。在这种情况下,由于A3不会覆盖此属性,因此与A1 :: x相同。 在第二个(gunc)中,您直接使用“ this”引用A1,因此没有问题。 在第三个(hunc,未使用)中,gunc带有对self的隐式引用。 (但我不确定)
此外,如果您添加A2类:
template<typename Context>
class A2 : public Context {
public :
int x{45678};
};
第一个将打印“ 45678”
如果现在您在保留A2的同时添加A3
template<typename Context>
class A3 : public Context {
public :
int x{67890};
};
第一个输出将是67890
答案 1 :(得分: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
}
};
最后一个问题:
int iunc() {
return Context::Context::A1::x;
}
在模板实例化后的内容如下
int iunc() {
return A3<A2<A1>>::Context::A1::x;
}
编译器现在抱怨类A3<A2<A1>>
中没有typedef,该类引入了名称Context
。 template参数仅在类模板中可见。