Предположим, у меня есть шаблонные классы
#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>>>
.
Примечание: gcc 8.2 с -O03 -std=c++17
производитодин и тот же код сборки в каждом случае.А именно, я скомпилировал код только с одной из функций 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
, параметр шаблона его параметра шаблона не является допустимым именем (или я неправильно назвал его в Context::Context::A1::x
).