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

#c #templates

#c #шаблоны

Вопрос:

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

 namespace
{
    struct hidden { };
}

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

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

Комментарии:

1. Какая версия g ? Может быть расширением

Ответ №1:

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

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


Да, в разделе 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
}