Проблема связана не с gcc, а с Visual Studio, которая принимает код, который не соответствует стандарту C ++.
На этом самом сайте уже был получен ответ, поэтому я буду краток.
Стандарт требует, чтобы шаблоны оценивались дважды:
- один раз в точке определения:
template <class T> struct Foo { void bar(); };
- один раз в точке экземпляра:
Foo<int> myFoo;
В первый раз все независимые имена должны быть выведены из контекста:
- компилятор сгенерирует, если вы забыли пунктуацию, ссылается на неизвестные типы / методы/ attribute
- компилятор выберет перегрузку для функций, задействованных в этой точке
Поскольку синтаксис C ++ неоднозначен, необходимо помочь синтаксическому анализатору на этом этапе и использоватьtemplate
и typename
ключевые слова для устранения неоднозначности вручную.
К сожалению, Visual Studio не соответствует требованиям и реализует только вторую оценку (в момент возникновения).ион).Преимущество для ленивых в том, что вы можете обойтись без лишних ключевых слов template
и typename
, недостаток в том, что ваш код плохо сформирован и не переносим ...
Теперь самое интересное:
void foo(int) { std::cout << "int" << std::endl; }
template <class T> void tfoo(T i) { foo(i); }
void foo(double) { std::cout << "double" << std::endl; }
int main(int argc, char* argv[])
{
double myDouble = 0.0;
tfoo(myDouble);
return 0;
}
Скомпилированный с gcc, он выводит int
.
Скомпилированный с Visual Studio, он выводит double
.
Проблема?Любой, кто повторно использует тот же символ, который вы используете в коде шаблона в VS, может натолкнуться на вашу реализацию, если его символ появится между включением кода шаблона и моментом, когда он фактически использует код шаблона ... не так ли?смешно: /?
Теперь для вашего кода:
template<typename T>
class Derived : public Base<T>
{
public:
void foo() { this->t = 4; this->get(); }
};
this
указывает, что следующее имя является зависимым именем , то есть оно зависит от T
(что не очевидно, когда символ появляется один).Поэтому компилятор будет ожидать инстанцирования и посмотреть, содержит ли инстанцированный вами шаблон конкретный тип Base<T>
эти методы.Это не обязательно, так как я мог бы прекрасно специализировать Base
:
// It's non-sensical to instanciate a void value,
template <>
class Base<void> {};
И, следовательно, Derived<void>
не должен компилироваться;)