Компилятор Visual C++ допускает использование зависимого имени как типа без "typename"?
Сегодня один из моих друзей сказал мне, что следующий код хорошо компилируется в его Visual Studio 2008:
#include <vector>
struct A
{
static int const const_iterator = 100;
};
int i;
template <typename T>
void PrintAll(const T & obj)
{
T::const_iterator *i;
}
int main()
{
std::vector<int> v;
A a;
PrintAll(a);
PrintAll(v);
return 0;
}
Я обычно использую g ++, и он всегда отказывается передавать второй вызов PrintAll(). Как я знаю, для этой проблемы g ++ выполняет стандартный способ перевода шаблона.
Итак, мои знания неверны или это расширение VS2008?
2 ответа
Это не расширение вообще.
VC++ никогда не реализовывал интерпретацию двух фаз должным образом:
- В точке определения проанализируйте шаблон и определите все независимые имена
- В момент создания экземпляра убедитесь, что шаблон создает правильный код
VC++ никогда не реализовывал первый этап... это неудобно, поскольку это означает не только то, что он принимает код, который не соответствует требованиям, но также и то, что он создает совершенно другой код в некоторых ситуациях.
void foo(int) { std::cout << "int" << std::endl; }
template <class T> void tfoo() { foo(2.0); }
void foo(double) { std::cout << "double" << std::endl; }
int main(int argc, char* argv[])
{
tfoo<Dummy>();
}
С этим кодом:
- совместимые компиляторы будут печатать "int", потому что это было единственное определение, доступное в момент определения шаблона и разрешения
foo
не зависит отT
, - VC++ напечатает "double", потому что он никогда не беспокоился о фазе 1
Это может показаться глупым с точки зрения различий, но если вы подумаете о количестве включений, которые у вас есть в большой программе, есть риск, что кто-то введет перегрузку после кода вашего шаблона... и BAM:/
Я не уверен, что "расширение" - это именно то, как я бы описал VC++ в этом отношении, но да, gcc имеет лучшую совместимость в этом отношении.