Suppose I have the templated classes
#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;
}
Inside the definition of the templated class A4
, at least when only the instance type A4<A3<A2<A1>>>
is used, it seems to be possible to refer to x
as either
this->A1::x;
or
Context::A1::x;
or
A1::x;
Question 1: Are these equivalent? Well, I think I can see them not being equivalent from the point of view of the templated class A4
viewed in isolation. For Context::A1::x
to work its template parameter should contain an x
. For this->A1::x
to work it should contain a scope called A1
, which in turn should contain an x
. And for A1::x
to work the scope of A4
itself should contain a scope called A1
containing an x
. My intention is to ask if they are equivalent from the point of view of the type A4<A3<A2<A1>>>
.
Nota bene: gcc 8.2 with -O03 -std=c++17
produces the same assembly code in each case. Namely, I compiled the code with only one of the functions func
, gunc
, and hunc
and only one call to the corresponding one, and this compiler produced identical executables. Of course, strictly speaking this doesn't necessarily imply that for the language in abstract those expressions are equivalent.
Question 2: How does the 'unpacking' of the scope of x
works in each case? Maybe this question doesn't make sense or is not exactly what I want to ask. Specially if the answer to Question 1 is that they are equivalent. Allow me modify this question after I find more information about Question 1, or ignore this question at first.
Note to Question 2: This observation might clarify why I am unsure how the unpacking works. If in the templated class A4
we had one more method
int iunc() {
return Context::Context::A1::x;
}
then the compilation fails with
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;
^
So, at least for gcc
at the moment that the type instance of A4
is being created, the template parameter of its template parameter is not a valid name (or I didn't name it properly in Context::Context::A1::x
).