GCC правильно.Шаблоны компилируются в два этапа: один раз, когда они анализируются, и один раз, когда они создаются.
Во время анализа проверяется все, что НЕ зависит от параметров шаблона, поэтому в этом случае Baz::Print
посмотрел вверх и обнаружил, что он не был объявлен, так что это ошибка.
Если вызов был T().Print()
или что-то еще, что зависело от типа T
, тогда поиск будет отложен до момента его созданиявремя (или хотя бы частично задержанное - см. ниже.)
Квалифицированные имена, такие как Baz :: Print, всегда ищутся во время определения, если только сама квалификация не зависит от параметра шаблона (например, T::Print
), хотяразрешение перегрузки откладывается на время создания экземпляра.Это означает, что вы не можете добавить в набор перегрузки квалифицированные имена после того, как шаблон был объявлен.
Неквалифицированные имена, такие как просто Print
, ищутся во время создания экземпляра, если какой-либо из аргументов функции зависит от шаблонапараметр.Таким образом, Print(T())
будет проверяться во время создания экземпляра, а Baz::Print(T())
- нет.Стоит отметить, что поиск во время создания экземпляра ограничен теми именами, которые видны в точке объявления, и теми, которые найдены через ADL, поэтому для Foo<int>
даже простой Print(T())
не должен найти Baz::Print
, если он был объявлен послеtemplate (как в примере).
Чтобы сделать пример кода работающим, либо определите Foo<T>::Bar
после определения Print
, либо опишите вперед Print
перед определением Foo
.