Шаблон доступа к символу в безымянном пространстве имен - PullRequest
1 голос
/ 26 марта 2010

Мы обновляем наш компилятор XL C / C ++ с V8.0 до V10.1 и обнаружили некоторый код, который теперь выдает нам ошибку, даже если он скомпилирован под V8.0. Вот минимальный пример:

test.h:

#include <iostream>
#include <string>

template <class T>
void f()
{
  std::cout << TEST << std::endl;
}

test.cpp:

#include <string>
#include "test.h"

namespace
{
  std::string TEST = "test";
}

int main()
{
  f<int>();
  return 0;
}

В V10.1 мы получаем следующую ошибку:

"test.h", line 7.16: 1540-0274 (S) The name lookup for "TEST" did not find a declaration.
"test.cpp", line 6.15: 1540-1303 (I) "std::string TEST" is not visible.
"test.h", line 5.6: 1540-0700 (I) The previous message was produced while processing "f<int>()".
"test.cpp", line 11.3: 1540-0700 (I) The previous message was produced while processing "main()".

Мы обнаружили аналогичное различие между g ++ 3.3.2 и 4.3.2. В g ++ я также обнаружил, что если я переместу #include "test.h" после объявления безымянного пространства имен, ошибка компиляции исчезнет.

Итак, вот мой вопрос: что Стандарт говорит об этом? Когда создается экземпляр шаблона, считается ли этот экземпляр объявленным в тот момент, когда был объявлен сам шаблон, или стандарт не очень ясен по этому вопросу? Я хоть немного посмотрел черновик n2461.pdf, но ничего не смог придумать.

Ответы [ 3 ]

5 голосов
/ 26 марта 2010

Это недопустимый код C ++. TEST не зависит от параметра шаблона T, поэтому его нужно найти в контексте определения шаблона при его анализе. Однако в этом контексте не существует объявления TEST, поэтому возникает ошибка.

Диагностическое сообщение для этого неправильно сформированного шаблона может быть отложено до создания экземпляром компилятором, но если компилятор исправен, он диагностирует ошибку раньше. Компиляторы, которые не выдают диагностическое сообщение для этого кода, даже когда создается экземпляр шаблона, не соответствуют. Это не имеет ничего общего с безымянными пространствами имен.

Кроме того, обратите внимание, что даже если вы поместите безымянное пространство имен над этим шаблоном, он не будет действительной программой C ++, даже если вы определите и вызовете этот шаблон в нескольких единицах перевода. Это связано с тем, что разные экземпляры одного и того же шаблона с одинаковыми аргументами шаблона будут ссылаться на разные вещи (строка в безымянном пространстве имен будет создавать новый объект каждый раз, когда он определен в другом модуле перевода). Поведение для такой программы будет неопределенным.

0 голосов
/ 26 марта 2010

Этот тест не проходит онлайн-компилятор Comeau , который в прошлом доказывал, что он является одним из самых совместимых со стандартами компиляторов. Тогда я бы склонялся к тому, чтобы код был неправильным в том виде, в котором он написан, хотя я не мог указать вам на строчку в стандарте, почему. Обратите внимание, что компиляция кода в расслабленном режиме завершается успешно.

0 голосов
/ 26 марта 2010

Помните, что #include просто копирует содержимое файла .h в файл .cpp. Итак, ваше определение f () появляется перед определением TEST. Лучший способ обойти это - добавить

extern std::string TEST;

вверху вашего .h файла.

...