Явная специализация члена
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 в вашем коде на самом деле является идентификатором шаблона.