Я комментировал чужой ответ, и они попросили меня вставить мой анализ здесь.
Я думаю, что ваш случай проблематичен, потому что Foo<true>
имеет объявление друга для функции члена Foo<false>
, которая в свою очередь относится к функции члена Foo<true>
. Хотя члены, соответственно, объявляются перед функциями-членами, этот тип циркулярной ссылки не поддерживается компиляторами. GCC жалуется на конкретизации
main.cpp: In instantiation of 'class Foo<false>':
main.cpp:9:12: required from 'class Foo<true>'
main.cpp:15:49: required from here
main.cpp:9:12: error: invalid use of incomplete type 'class Foo<true>'
friend Foo<!B>::Foo(Foo<B>&);
Это сообщение об ошибке немного сбивает с толку, поскольку она предполагает, что неполные типы не могут быть использованы с ::
, что неправильно. Определяемый класс может использоваться с ::
, даже если он еще не завершен. Класс, который создается экземпляром, по-разному обрабатывается GCC, чем класс, который определяется, и ссылка на класс, который создается экземпляром в квалифицированном имени, по-видимому, не поддерживается GCC.
У нас есть DR о таких циклических ссылках, http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#287, которые, как представляется, делают это законным, но, как говорится в заключительном заявлении, «Это требует работы», поэтому GCC имеет право отклонить ваш код, который я бы сказал. Чтобы добавить к этой путанице, у нас также есть явное правило для имен, используемых в объявлениях функций друга, которые не упоминаются в DR287, и его «как будто» сделает ваш код плохо сформированным, потому что точка создания экземпляра Foo<!B>
непосредственно перед точка инстанцирования Foo<B>
и, если мы не применим правило в DR287, не может увидеть объявление конструктора Foo<B>
.
Классы или функции класса могут быть объявлены в шаблоне класса. При обработке шаблона, имена его друзей рассматриваются как если специализация была объявлена явно в его точке конкретизации
Независимо от этого, есть еще одна проблема под рукой: Является ли Foo<!B>::Foo(Foo<B>&);
со ссылкой на конструктор? Это ссылка на конструктор, если она ссылается на введенное имя класса, которое компилятор тогда должен рассматривать как конструктор в этих constexts. Поэтому компилятор должен решить Foo<!B>::Foo
.Но Foo<!B>
- зависимый тип, поэтому компилятор не может заглянуть в него, чтобы решить, какое это имя (помните, что разрешено struct A { int A; }
, и компилятор должен убедиться, что он не в такой ситуации). Я думаю, по этим причинам, cland не удается разобрать ваш шаблон, потому что он смущен относительно того, что означает friend Foo<!B>::Foo(Foo<B>&)
.
Я считаю, сама (без учета вопросов конкретизации) шаблон должен быть хорошо образован, потому что компилятор может просто задержать поиск по Foo<!B>::Foo
и принять его как не тип, который он на самом деле является (Конструкторы).
Благодарим вас за то, что вы очень информативный ответ. Таким образом, мой единственный способ пойти - это объявить, что все кластерное задание шаблона является другом, не так ли? – Poroing
@user правильный, я так думаю. Но, возможно, вы можете переместить код, который нуждается в частном доступе к функции-члене и подружиться с функцией-членом. –
О, мне нравится, что вы идете переместить код в другую функцию-член, я посмотрю, смогу ли я сделать что-то хорошее , Спасибо вам большое. – Poroing