Явная специализация члена

g++ 3.4.5 принимает этот код:

template <typename T> struct A
{
    static const char* const str;
};

struct B {};

typedef A<B> C;

template<> const char* const C::str = "B";
// Equivalent to following?
// template<> const char* const A<B>::str = "B";

Но я не уверен, что это на самом деле законно C++03. Особенно,

[14.7p3] В явном объявлении специализации для шаблона класса, члена шаблона класса или шаблона члена класса, имя класса, который явно специализирован, должно быть идентификатором шаблона.

Говорит ли это требование, что в конце этого примера должна использоваться версия без определения типа? Или я что-то неправильно истолковал?

Изменить: Еще одно свидетельство: Отчет о дефекте 403 предполагает, что неверно говорить, что тип (в этом контексте тип аргумента выражения вызова функции) является идентификатором шаблона, потому что идентификатор шаблона имеет синтаксическое значение, а не семантическое один. В последующих проектах стандарта использовалась "специализация шаблона класса" вместо " template-id " в 3.4.2.

Это поддерживает аргумент, что хотя A<B> а также C представляют один и тот же тип (и имеют идентичное или почти идентичное семантическое значение), A<B> это идентификатор шаблона и C нет, потому что термин шаблон-идентификатор относится к синтаксическому содержимому как к последовательности токенов, а не к значению этих токенов.

2 ответа

Решение

Я думаю, что это строго неправильно (по крайней мере, в соответствии с C++ '03).

Моя логика заключается в том, что хотя typedef (7.1.3 / 1):

... таким образом, является синонимом для другого типа.

В стандарте все еще есть слова, которые явно позволяют использовать typedef, где class-name требуется (7.1.3/4):

Typedef-name, которое называет класс, является class-name

Там нет таких слов для template-id,

Я предполагаю, что явная специализация не имеет место там. Вы можете написать подобный код без шаблонов:

struct A
{
    static const char* const str;
};

typedef A C;

const char* const C::str = "B";

Этот код абсолютно корректен, даже если вы используете C вместо A. C - просто псевдоним.

Просто представьте, как обрабатывается код C++. Очевидно, что typedefs расширяются компилятором еще до запуска процесса создания шаблона. Так же, как все комментарии раскрываются перед макросами. Поскольку все макросы раскрываются препроцессором еще до начала фактического синтаксического анализа C++. Это все упрощает.

Что касается стандарта C++03, взгляните на это

7.1.3/1 Имя, объявленное с помощью спецификатора typedef, становится typedef-name. В рамках своей декларации typedef-name синтаксически эквивалентно ключевому слову и называет тип, связанный с идентификатором, способом, описанным в разделе 8. Таким образом, typedef-name является синонимом для другого типа. Typedef-name не вводит новый тип, как объявление класса (9.1) или enum.

Я предполагаю, что этот параграф ясно объясняет, что C в вашем коде на самом деле является идентификатором шаблона.

Другие вопросы по тегам