Разве функции членства шаблонного класса не компилируются при инстанцировании?

Я нашел странную проблему при портировании моего кода от Visual Studio до gcc. Следующие компиляции кода, прекрасные в Visual Studio, но результатах по ошибке в gcc.

namespace Baz
{
   template <class T>
   class Foo
   {
   public:
      void Bar()
      {
         Baz::Print();
      }
   }; 

   void Print() { std::cout << "Hello, world!" << std::endl; }
}

int main()
{
   Baz::Foo<int> foo;
   foo.Bar();

   return 0;
}

Мое понимание - то, что это должно скомпилировать OK, поскольку класс не должен быть скомпилирован, пока шаблон не инстанцируют (который является после того, как Печать () определяется). Однако gcc сообщает о следующем:

t.cpp: В функции членства 'освобождают Baz:: Нечто:: Панель ()': Строка 8: ошибка: 'Печать' не является членом 'Baz'

Кто прав? И если gcc является правильным, почему?

5
задан Shirik 15 July 2010 в 17:29
поделиться

2 ответа

gcc прав. Это потому, что Baz - пространство имен, а пространства имен разбираются сверху вниз, поэтому объявление Baz::Print не видно изнутри Foo (поскольку оно находится под ним).

При инстанцировании шаблона учитываются только имена, видимые из определения шаблона, без учета поиска Кёнига (что ничего не изменит в вашем случае).

Если бы Baz был структурой или классом, ваш код работал бы, поскольку они разбираются в два этапа (сначала объявления, затем тела), поэтому все, что объявлено в структуре или классе, видно внутри, например, функций-членов, независимо от их порядка в исходном файле.

Вы можете заставить это работать, объявив Baz::Print перед Foo.

Цитирую стандарт:

14.6.3 Независимые имена

Независимые имена, используемые в определении шаблона, находятся с помощью обычного поиска имен и связываются в том месте, где они используются. в месте их использования.

14.6.4 Разрешение зависимых имен

При разрешении зависимых имен рассматриваются имена из следующих источников:

  • Объявления, видимые в момент определения шаблона.
  • Объявления из пространств имен, связанных с типами аргументов функции как из контекста инстанцирования (14.6.4.1) и из контекста определения.

(конец цитаты)

Когда Print не является зависимым (как сейчас), он не будет найден, так как его ищут до его объявления (в контексте определения шаблона). Если бы он был зависимым, то не было бы первого случая (так же, как и в случае, когда он не является зависимым), а Baz никак не связан с int (параметром шаблона), поэтому он не будет искаться и во втором случае.

4
ответ дан 18 December 2019 в 16:34
поделиться

gcc прав. Шаблоны компилируются в два этапа: один раз при их анализе и один раз при их создании.

Во время синтаксического анализа проверяется все, что НЕ зависит от параметров шаблона, поэтому в этом случае выполняется поиск Baz :: Print и обнаруживается, что он не был объявлен, так что это ошибка .

Если бы звонок был T ().Print () или что-то еще, зависящее от типа T , тогда поиск будет отложен до времени создания экземпляра (или, по крайней мере, частично отложен - см. Ниже).

Полные имена, такие как Baz: : Print всегда просматривается во время определения, если сама квалификация не зависит от параметра шаблона (например, T :: Print ), хотя разрешение перегрузки откладывается до времени создания экземпляра. Это означает, что вы не можете добавить к набору перегрузки полные имена после объявления шаблона.

Неквалифицированные имена, такие как просто Print , просматриваются во время создания экземпляра, если какой-либо из аргументов функции зависит от параметра шаблона. Таким образом, Print (T ()) будет просматриваться во время создания экземпляра, а Baz :: Print (T ()) - нет. Стоит отметить, что поиск во время создания экземпляра ограничен теми именами, которые видны в точке объявления и теми, которые были найдены через ADL, поэтому для Foo даже простой Print (T () ) не должен находить Baz :: Print , если он был объявлен после шаблона (как в примере).

Чтобы пример кода работал, либо определите Foo :: Bar после определения Print , либо выполните прямое объявление Print перед определение Foo .

8
ответ дан 18 December 2019 в 16:34
поделиться
Другие вопросы по тегам:

Похожие вопросы: