Код ниже компилируется без предупреждения на GCC и выдает ошибку с clang (любые c ++ 11-совместимые версии clang и GCC).Какой компилятор прав по отношению к стандарту?В частности, разрешено ли объявлять в качестве друга не частично специализированный шаблонный псевдоним, который является частичной шаблонной специализацией класса?
Это заставляет меня думать, что это не может быть разрешено:
- cppreference говорит: " Объявления друзей не могут ссылаться на частичные специализации [...]".
- А также: «Объявление псевдонима типа вводит имя, которое может использоваться как синоним для типа, обозначаемого идентификатором типа. Оно не вводит новый тип [...] ".
- Наконец:" И шаблон функции и объявления шаблона класса могут появляться с указателем друга [...] ".Это неявно исключает возможность того, что псевдоним шаблона может быть другом класса в качестве фактического псевдонима шаблона, а не в качестве шаблона псевдонима класса, что является частичной специализацией в приведенном ниже фрагменте.
Однакоэто заставляет меня думать, что это может быть разрешено:
- cppreference говорит: " Шаблон псевдонима - это шаблон [...]".Я понимаю, что псевдоним шаблона - это отдельный шаблон.Следовательно, объявление его в качестве друга, как в следующем примере, без частичной спецификации псевдонима шаблона класса, допустимо ... Или нет.
- Этот код (не от меня) также даетОбходной путь и позвольте мне думать, что нет никаких очевидных причин для того, чтобы сделать следующий код некорректным.
В этом посте задается очень похожий вопрос, но в отношениик конкретному использованию промежуточного псевдонима шаблона.
template<typename T,typename N> class B{};
template<typename T> class A{
// template<typename U> friend class B<T,U>; fails as expected
template<typename N> using alias = B<T,N>;
template<typename N> friend class alias;
};
Намерение: законный способ объявить частичную специализацию другом, используя промежуточный псевдоним (обходной путь).
Результат: GCC доволенэто и производит намеченное поведение.Clang выдает следующую ошибку:
<source>:7:35: error: redefinition of 'alias' as different kind of symbol
template<typename N> friend class alias;
^
<source>:6:22: note: previous definition is here
template<typename N> using alias = B<T,N>;