Компиляторы (clang-5.0.0, GCC-7.3, ICC-18 и MSVC-19) расходятся по доступности членов A ниже.
class A {
template <class> static constexpr int f() { return 0; }
template <int> struct B {};
template <class T> using C = B<f<T>()>;
};
Действительно, рассмотрим следующие способы использования:
template <class T> using D = A::C<T>;
int main() {
// | clang | gcc | icc | msvc
(void) A::f<int>(); // 1: | f | f | f | f, (C)
(void) A::B<0>{}; // 2: | B | | B | B, (C)
(void) A::C<int>{}; // 3: | C, f | | C | C
(void) D<int>{}; // 4: | f | | C | C
}
В таблице справа показано, какие члены должны быть опубликованы каждым компилятором для принятия кода (при компиляции для С++ 14).
ИМХО, ICC и MSVC (игнорируя (C) записи) выглядят корректно. За исключением первой строки, GCC, похоже, полностью игнорирует доступность.
Я не согласен с clang, когда требуется, чтобы f был общедоступным для создания экземпляров A::C<int> и D<int>. Как и ICC и MSVC, я думаю, что C и только C должны быть публичными. Это правда, что C использует f но разве это не деталь реализации? Обратите внимание, что C также использует B Если clang были верны, то почему он не требует, чтобы B был публичным?
Наконец, давайте рассмотрим записи (C). MSVC требует, чтобы C был общедоступным, когда он впервые встречает определение D, то есть MSVC жалуется на то, что C является частным.
Мои вопросы:
- Прав ли я (и ICC) в моем анализе? Иначе какой другой компилятор верен и почему?
- Является ли проблема MSVC еще одним воплощением ошибки двухфазной реализации в msvc?
Обновление: Что касается GCC, похоже, это ошибка, о которой сообщалось в комментарии 8, здесь.