Предположим, что есть такой код:
template <typename T>
CLASS_KEY1 X{};
PREFIX template CLASS_KEY2 X<int>;
где CLASS_KEY1
, CLASS_KEY2
и PREFIX
- это макросы. CLASS_KEY1
и CLASS_KEY2
могут быть расширены до ключевых слов class
, struct
или union
. PREFIX
может быть расширен до пустого набора символов или ключевого слова extern
.
Вот таблица, которая показывает, когда такой код компилируется (Yes
- компилирует, No
- не компилирует) для всех комбинаций значений макросов (компилятор gcc-4.8.1, опция -std=c++11
):
PREFIX extern extern extern
CLASS_KEY1\CLASS_KEY2 class struct union class struct union
class Yes Yes? No Yes Yes? No
struct Yes? Yes No Yes? Yes No
union No No Yes No No Yes
Это ошибка в gcc или стандартном требовании (странные случаи помечены вопросительными знаками)? А как насчет других компиляторов?
Раздел 7.1.6.3 (спецификаторы специфицированного типа) стандарта С++ 11 гласит:
Ключевое слово класса или
enum
присутствующее в специфицированном спецификаторе типа, должно согласовываться в натуральной форме с объявлением, к которому относится имя в спецификаторе разработанного типа. Это правило также относится к форме специфицированного спецификатора типа, объявляющего класс-имя или классfriend
поскольку это может быть истолковано как относящееся к определению класса. Таким образом, в любом специфицированном спецификаторе типа ключевое словоenum
должно использоваться для ссылки на перечисление (7.2), ключ классаunion
должен использоваться для ссылки наunion
(раздел 9) иclass
илиstruct
-key должен использоваться для обозначенияclass
(пункт 9) объявляется с помощьюclass
илиstruct
класса ключа.
Таким образом, поведение, которое вы видите, разрешено.
struct
иclass
. Могу поспорить, что сохраненная политика объявлена, когда класс определяется.warning: class template 'X' was previously declared as a struct template
. Оба компилятора применяют политику инкапсуляции, объявленную там, где определен класс.