6

Следующий исходный код привезен из: Understanding partial specialization of inherited nested class templatesСпециализация наследственного вложенного шаблонного класса

#include <type_traits> 
struct Base 
{ 
    template<class U, class _ = void> struct Inner: std::true_type {}; 
    template<class _> struct Inner<char, _>: std::false_type {}; 
}; 
struct Derived : Base 
{ 
}; 

template<class _> struct Derived::Inner<int, _>: std::false_type {}; 

У меня был вопрос о том, специализирующихся унаследованном классе, так что я гугл, и выяснить этот вопрос выше. Исходный код в вопросе выше скомпилирован без какой-либо проблемы в gcc/clang, но msvc отказывается его компилировать, выдавая C2427 (см. https://msdn.microsoft.com/en-us/library/10het5hx.aspx).

Ситуация выше (специализируется на вложенном шаблоне класса класса, отличного от шаблона) сильно отличается от ситуации, описанной в https://msdn.microsoft.com/en-us/library/10het5hx.aspx (определение вложенного класса без шаблона класса шаблона), я думаю.

Какая из msvc vs. gcc/clang неверна? Или просто стандарт настолько неясен, чтобы указать это поведение?

Я надеюсь, что MSVC не так ...

ответ

2

Clang и GCC являются неправильными, и MSVC и АДГ являются право отклонить это частичное определение специализации.

Частичная специализация сама по себе является шаблоном, а определение шаблона класса синтаксически сконструировано с точки зрения определения класса (в грамматических терминах, ) класса). В рамках такого определения Derived::Inner<int, _> является классом-заголовком, с Derived::, являющимся вложенным именем-спецификатором.

[9p11] в Стандарте говорит:

Если класс-голова-имясодержит вложенного-имя-спецификатор, то класса спецификатора должны относиться к классу, который ранее было объявлено непосредственно в классе или пространстве имен, к которому относится вложенное имя-спецификатор , или в элементе встроенного пространства имен (7.3.1) этого пространства имен (то есть не просто унаследовано o r введено в с использованием декларации), а спецификатор класса должен появиться в пространстве имен , содержащем предыдущее объявление. [...]

Итак, вы должны использовать Base::Inner<int, _>.


Как отмечалось в комментариях выше цитата относится к шаблона класса определения явной специализации, а также (их производство грамматику также заканчивается использованием-головы имя-класса ).


Нижеприведенный пример не применим непосредственно к вашему примеру, но я счел нужным упомянуть его.

Обратите внимание, что выше цитата относится к шаблону класса (или явной специализации) определения, а не декларации, таким как

template<class _> struct Derived::Inner<int, _>; 

Синтаксический, struct Derived::Inner<int, _> в есть разработан типа-спецификатор, к которой пункт выше не применяется. Таким образом, стандартная формулировка технически допускает такие заявления.

Это, кажется, не обозревают: формулировка выше была введена постановлением DR284, который включает в свой комментарий:

Чувство, что это должно быть обязательно определения классов, но а не на спецификаторах специфицированных типов вообще (которые являются ссылками , а не декларациями). [...]

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

Однако ни MSVC, ни EDG не принимают такие объявления (и, откровенно говоря, я смущаю, если бы они это сделали). Комментарий в DR, по-видимому, указывает на то, что целью было разрешить только спецификатора, которые также не являются декларациями, но похоже, что это не отразилось на формулировке (стандартная ошибка, я думаю).

+0

Это очень плохо ... Было бы очень приятно, если бы я мог специализировать вложенный шаблон класса с использованием имени производного класса ... В любом случае, спасибо за очень информативный ответ! Кстати, [9p11] применяется также к явной специализации? Кажется, что msvc все еще отказывается, когда я удалял параметр фиктивного в примере. –

+0

@JunekeyJeon Да, это так, насколько я могу судить. – bogdan

Смежные вопросы