Ответ 1
Я думаю, что ни один из этих вызовов не должен работать вообще, и что Кланг прав, по крайней мере, отвергая первый.
Стандарт C++ гласит:
Друг шаблона класса или класса может быть шаблоном функции или шаблоном класса, специализацией шаблона функции или шаблона класса или функцией или классом без шаблона. Для объявления функции друга, которое не является объявлением шаблона:
- если имя друга является квалифицированным или неквалифицированным идентификатором шаблона, декларация друга относится к специализации шаблона функции, в противном случае [...]
Имя вашей функции-друга void A::create
, безусловно, является идентификатором шаблона, так как A::create
- это шаблон. Таким образом, вы заявили, что экземпляр шаблона A::create<B>
является другом (любым экземпляром) B
Это даже кажется законным, поскольку стандарт говорит:
Аргумент шаблона для параметра-шаблона, который является типом, должен быть идентификатором типа.
Проверяя грамматику, это даже кажется прекрасным:
type-id: type-specifier-seq [...]
Тип-спецификатор: простой тип-спецификатор [...]
type-specifier-seq: type-specifier [...]
простой тип-спецификатор:
inested-name-specifier opt
[...]
inested-name-specifier opt
Имя Шаблона
Однако это объявление друга просто бесполезно, так как вы не можете определить шаблон, который бы принял сам шаблон (B
) в качестве аргумента.
Clang и GCC, похоже, согласуются с этим, поскольку компилируются A::create<B>();
не создает какой-либо синтаксической ошибки или сообщения о неквалифицированном типе, но они говорят вам, что нет соответствующего шаблона. Clang:
error: no matching function for call to 'create'
A::create<B>();
GCC:
error: no matching function for call to ‘A::create()
A::create<B>();
Я не могу найти ничего в стандарте, который бы объяснил, почему friend void A::create<B>();
сделало бы все экземпляры A::create
с инстанцированием B в качестве первого аргумента шаблона другом A. Следовательно, также последняя строка (create<B<int>>();
) должна вызвать ошибку.
Ошибка, упомянутая в комментариях, не кажется связанной. Стандарт определяет, что
Шаблон друга может быть объявлен в шаблоне класса или класса. [...] В этих случаях все специализации шаблона класса друзей или друзей являются друзьями шаблона класса или класса, дающего дружбу.
Минимальный тестовый пример, представленный там, ясно показывает, что это поведение каким-то образом нарушается в Кланге.