Может ли шаблон класса явной специализации также объявить что-то еще? - PullRequest
11 голосов
/ 10 июня 2011

Было бы неплохо, если бы этот код был неверным. Но это концептуально звучит, и GCC принимает его , хотя Comeau этого не делает:

template< typename > struct t;

template<> struct t< int > {} r; // Bad declarator! Don't pee on the carpet!

( Редактировать: вышеприведенные компиляции, но r кажется, не объявляется в любой области , так что это по существу игнорируется.)

Явные специализации заполняют некую область между шаблонами и классами. Тип, объявленный явной специализацией, завершается после его определения. С точки зрения компилятора, это не шаблон. Если бы это был параметризованный шаблон, объявление объекта было бы невозможно. Рассмотрим §14 / 3:

В объявлении шаблона, явной специализации или явном создании список инициаторов объявления в объявлении должен содержать не более одного декларатора. Когда такое объявление используется для объявления шаблона класса, объявление не допускается.

Что означает «используется для объявления шаблона класса»? Понятно, что основной шаблон объявляет шаблон класса. И частичная специализация тоже, согласно §14.5.5 / 1 (номера FDIS):

Объявление шаблона, в котором имя шаблона класса представляет собой простой-идентификатор шаблона, является частичной специализацией шаблона класса, указанного в простом-шаблоне-идентификаторе.

Однако, когда дело доходит до явных специализаций, Стандарт говорит в терминах декларации, которой предшествует последовательность токенов template<>. Он выглядит как шаблон и называет имя шаблона, но, похоже, он не объявляет шаблон.

Действительно странной вещью является то, что §14 / 3 ограничивает количество объявлений до «не более одного». Объявление шаблона функции, явная специализация или создание должны иметь ровно один декларатор. Любое объявление, включающее шаблон класса, должно иметь ровно ноль ... кроме явной специализации, которая, похоже, проваливается. К счастью, GCC отказывается разрешить

template<> struct t< int > {} r, s; // Offer valid one per specialization.

Я склонен согласиться с интерпретацией GCC, чушь, как это может быть. К сожалению, это может ингибировать его способность обнаруживать пропущенные точки с запятой. Пожалуйста, пусть количество разрешенных деклараторов будет точно равно нулю!

Ответы [ 2 ]

13 голосов
/ 10 июня 2011

Несколько моментов: во-первых, явные специализации не в никуда область между шаблонами и классами; явная специализация класс, период. Единственное отношение имеет с шаблонами (за исключением смешное имя) в том, что он будет использоваться вместо шаблона если шаблон должен быть создан для типа специализации.

Во-вторых, если есть проблема с параграфом в §14 / 3, что вы цитировать, это то, что оно включает в себя явную реализацию; явный инстанцирование является определением класса, и если

struct S {} s, *p;

законно,

template<> struct T<int> {} s, *p;

тоже должно быть. (Я бы поспорил против разрешения либо, но этот поезд уже покинул станцию, и так как C позволяет первый, мы застряли с этим.)

В противном случае утверждение в §14 / 3 немного не имеет значения. Функция шаблон должен иметь ровно один декларатор и шаблон класса точно нуль; нет необходимости пытаться объединить их обоих в "самое большее" абракадабра. (Если бы я разрабатывал язык с нуля, я бы не стал разрешить любому объявителю в объявлении, которое определило класс или перечисление тип. Но опять же, для этого уже слишком поздно.)

И я согласен, что это беспокоит:

template<> struct T<int> {};    //  Requires a ';'
template<> void f<int>() {}     //  ';' forbidden

(По крайней мере C ++ 11 разрешит точку с запятой после определения функции.)

1 голос
/ 20 июня 2011

Явная специализация и явная реализация не объявляют шаблон.Они объявляют template-id , который ссылается на специализацию, которая является классом.

Однако это не подтверждает мой пример.Проблема в том, что все , объявленное после template или template<>, является частью явной реализации или специализации, соответственно.Только определенные типы объектов могут быть специализированными или созданными, и ранее необъявленные имена не являются одним из них.

Рассмотрим эти примеры, делающие необоснованное, но легальное использование разработанных спецификаторов типов (§7.1.5.3):

template< typename T > struct s;
template< typename T > s< int > *f() {}

template<> struct u *f< char >(); // struct u is declared
u *p = 0; // see, we can use its name now.
template<> struct s< int > *f< int >(); // s<int> declared but not specialized
template struct s< int > *f< long >(); // s<int> declared but not instantiated

Насколько я могу судить, Стандарт нечетко указывает, какое объявленное имя является специализированным.Язык слабо подразумевает, что каждое такое объявление применяется только к одному шаблону: §14.7.2 / 2

Если явное создание экземпляра для класса, функции или специализации шаблона члена ...

и §14.7.3 / 2

В пространстве имен, членом которого является шаблон, должна быть объявлена ​​явная специализация…

Чтобы решить эту проблему, нужно проигнорировать объявление типа, если в деклараторе также указана легальная реализация / специализация.

В заключение, примеры в этом вопросе указывают недопустимые специализации в деклараторе изатем ожидайте, что компилятор вернется назад и вместо этого специализирует тип.Учитывая явные списки того, что специализациям и объявлениям разрешено делать в §14.7.2 / 1 и §14.7.3 / 1, кажется более разумным жаловаться на template<> struct t< int > {} r;, что r не является шаблоном функции, функцией-членомшаблон, статический член данных шаблона класса и т. д.

...