Ответ 1
Вопросы A::f<int>()
и A::B<0>
являются прямыми для ответа. f
и B
являются частными, и у них нет других интересных зависимостей. Доступ к ним должен быть плохо сформирован. gcc, как правило, очень правдоподобно в отношении контроля доступа в шаблонах, для всех видов ситуаций существует метабог (я думаю, что все они имеют такую форму, что gcc разрешает доступ, когда это не должно, а не запрещает доступ, когда это необходимо).
Интереснее вопрос A::C<int>
. Это шаблон псевдонима, но в каком контексте мы действительно просматриваем псевдоним? Является ли он внутри A
(в этом случае, если C
будет достаточным) или он будет использоваться в контексте, в котором он используется (в этом случае все f
, B
и C
должны быть доступны). Этот вопрос - именно CWG 1554, который все еще активен:
Взаимодействие шаблонов псевдонимов и контроля доступа не ясно из текущей редакции 17.6.7 [temp.alias]. Например:
template <class T> using foo = typename T::foo; class B { typedef int foo; friend struct C; }; struct C { foo<B> f; // Well-formed? };
Является ли замена
B::foo
дляfoo<B>
выполненной в контексте подкласса классаC
, что делает корректную формулу ссылки, или это доступ определен независимо от контекста, в котором появляется спецификация шаблона псевдонимов?Если ответ на этот вопрос заключается в том, что доступ определяется независимо от контекста, необходимо следить за тем, чтобы отказ доступа по-прежнему считался "в непосредственном контексте типа функции" (17.9.2 [temp.educt ], пункт 8), так что это приведет к отказу от вычета, а не к жесткой ошибке.
Хотя проблема все еще остается открытой, направление выглядит следующим образом:
Консенсус CWG заключался в том, что создание экземпляров (поиск и доступ) для шаблонов псевдонимов должно быть таким же, как и для других шаблонов, в контексте определения, а не в контексте, в котором они используются. Однако они все равно должны быть расширены.
Иными словами, только C
необходимо обнародовать, а f
и B
могут оставаться закрытыми. Так интерпретируют ICC и MSVC. У Clang есть ошибка, которая позволяет шаблонам псевдонимов обходить доступ (15914), поэтому clang требует, чтобы f
был доступен, но не B
Но в противном случае clang, похоже, расширяет псевдоним в точке использования, а не в точке определения.
Вопрос D<int>
должен просто следовать A::C
точно, никаких проблем с CWG 1554 здесь нет. Clang - единственный компилятор, который может иметь различное поведение между A::C
и D
, снова из-за ошибки 15914.
Подводя итог, вопрос A::C
- проблема открытого ядра, но ICC реализует намеченное значение языка здесь. У других компиляторов есть проблемы с проверкой доступа и шаблонами.