Внутренний тип в качестве аргумента шаблона

Стандарт ISO 98/03 (раздел 14.3.1), по-видимому, запрещает использование типа с внутренней связью в качестве параметра шаблона. (См. Пример ниже.) В стандарте С++ 11 нет. g++ - с использованием старого стандарта - позволяет это. Я неправильно читаю стандарт 03 или g++ просто разрешаю этот слайд?

namespace
{
    struct hidden { };
}

template<typename T>
struct S
{
   T t;
};

int main()
{
    S<hidden> s;
    return 0;
}

Ответ 1

Вы правы, что С++ 03 не разрешает использовать тип с внутренней связью в качестве параметра типа шаблона, тогда как С++ 11. делает.

Мне кажется, однако, что определения внутри анонимного пространства имен по-прежнему имеют внешнюю связь.


Yup, раздел 3.5 [basic.link] говорит

Имя, имеющее область пространства имен (3.3.5), имеет внутреннюю связь, если это имя

  • шаблон объекта, ссылки, функции или функции, который явно объявлен статическим или,
  • объект или ссылка, которая явно объявлена ​​ const, и ни одно явно объявленное extern и ранее не объявленное иметь внешнюю связь; или
  • член данных анонимного объединения.

Имя, имеющее область пространства имен, имеет внешнюю связь, если это имя

  • объект или ссылку, если он не имеет внутренней связи; или
  • функция, если она не имеет внутренней связи; или
  • названный класс (раздел 9) или неназванный класс, определенный в объявлении typedef, в котором класс имеет имя typedef для целей привязки (7.1.3); или
  • именованное перечисление (7.2) или неназванное перечисление, определенное в объявлении typedef, в котором перечисление имеет имя typedef для целей привязки (7.1.3); или
  • перечислитель, относящийся к перечислению с внешней связью; или
  • шаблон, если он не является шаблоном функции, который имеет внутреннюю связь (раздел 14); или
  • пространство имен (7.3), если оно не объявлено в неназванном пространстве имен.

У вас есть именованный класс в области пространства имен, он имеет внешнюю связь.

И в сноске внизу страницы 115 ISO/IEC 14882: 2003 разъясняется:

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

Если у вас есть другая версия, попробуйте посмотреть в разделе 7.3.1.1 [namespace.unnamed]

Ответ 2

Это не допустимый пример правила. Класс hidden в вашем примере имеет внешнюю привязку. (У него есть уникальное имя, генерируемое компилятором, так что ничто вне существующей единицы перевода не может фактически связываться с ним, но оно все еще является внешним.)

В стандарте приведен пример локального типа:

template <class T> class X { /* ... */ };
void f()
{
  struct S { /* ... */ };

  X<S> x3;  // error: local type used as template-argument
  X<S*> x4; // error: pointer to local type used as template-argument
}