Подтвердить что ты не робот

Доступ к унаследованной переменной из шаблонного родительского класса

Рассмотрим следующий код:

template<class T> class Foo
{
public:
  Foo() { a = 1; }

protected:
  int a;
};

template<class T> class Bar : public Foo<T>
{
public:
  Bar() { b = 4; };

  int Perna(int u);

protected:
  int b;

};

template<class T> int Bar<T>::Perna(int u) 
{ 
  int c = Foo<T>::a * 4; // This works
  return (a + b) * u;    // This doesn't
}

g++ 3.4.6, 4.3.2 и 4.1.2 дают ошибку

test.cpp: In member function `int Bar<T>::Perna(int)':
test.cpp:25: error: `a' was not declared in this scope

g++ 2.96 и MSVC 6, 7, 7.1, 8 и 9 принимают его, как это делают (по крайней мере) более старые компиляторы Intel и SGI С++.

Выполняет ли новый компилятор Gnu С++ стандарт или нет? Если это так, то в чем смысл этого наследующего класса не может видеть защищенную унаследованную переменную-член?

Кроме того, если есть

int A() { return a; } 

в Foo, я получаю ошибку

test.cpp:25: error: there are no arguments to A that depend on a template parameter, so a declaration of A must be available
test.cpp:25: error: (if you use -fpermissiveâ, G++ will accept your code, but allowing the use of an undeclared name is deprecated)

когда я пытаюсь использовать его в функции-члене Bar. Мне также кажется, что это любопытно: Bar наследует Foo, поэтому я считаю очевидным, что A() в области Bar - Foo:: A().

4b9b3361

Ответ 1

Более поздние версии GCC корректно реализуют стандарт.

В стандарте указано, что неквалифицированные имена в шаблоне не зависят и должны быть просмотрены при определении шаблона. Определение зависимого базового класса в это время неизвестно (могут существовать специализированные шаблоны базового класса), поэтому неквалифицированные имена не могут быть разрешены.

Это верно для имен переменных и функций, объявленных в базовом классе.

Как вы заметили, решение состоит в том, чтобы предоставить квалифицированное имя переменной или функции или предоставить объявление "использование". Например.

template<class T> 
int Bar<T>::Perna(int u) 
{ 
  int c = Foo<T>::a * 4; // This works
  c = this->a * 4; // and this

  using Foo<T>::a; 
  c = a * 4; // and with 'using', so should this
}

(Я на самом деле не уверен на 100% относительно правильного синтаксиса для используемой версии и не могу проверить здесь, но вы получаете идею).

Ответ 2

Сообщение об ошибке, которое GCC дает, показывает, что ваша версия GCC по-прежнему имела ошибку, которая разрешена только в версиях соединительных линий GCC4.7. Старые версии, в том числе GCC4.1, с радостью принимают следующий код

template<typename T>
struct A {
  void f(int) { }
};

template<typename T>
struct B : A<T> {
  void g() { T t = 0; f(t); }
};

int main() {
  B<int> b; b.g();
}

GCC будет искать f в f(t) в базовом классе A<T> и найдет объявление в базовом классе. GCC делает это, потому что f зависит, потому что есть аргументы f, которые "зависят от параметра шаблона" (посмотрите на его сообщение об ошибке, которое оно вам дало!). Но стандарт запрещает GCC делать это по двум причинам.

  • В стандарте говорится, что использование неквалифицированных имен никогда не найдет объявление в зависимом базовом классе независимо от того, зависит ли имя.

  • В стандарте говорится, что зависимый поиск имени функции во время создания экземпляра будет выполнять только ADL.

GCC 4.7 правильно использует Стандарт в этом отношении.