Compilers (clang-5.0.0
, GCC-7.3
, ICC-18
and MSVC-19
) diverge w.r.t. accessibility of members of A
below.
class A {
template <class> static constexpr int f() { return 0; }
template <int> struct B {};
template <class T> using C = B<f<T>()>;
};
Indeed, consider the following usages:
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
}
The table on the right shows which members each compiler requires to be made public to accept the code (when compiled for C++14).
IMHO, ICC and MSVC (ignoring (C)
entries) look correct. Except for the first line, GCC seems to be completely ignoring accessibility.
I disagree with clang when it requires f
to be public to instantiate A::C<int>
and D<int>
. Like ICC and MSVC, I think C
and only C
needs to be public. It is true that C
uses f
but is it not an implementation detail? Notice that C
also uses B
. If clang were correct, then why does it not require B
to be public as well?
Finally, let us consider the (C)
entries. MSVC requires C
to be public when it first encounters the definition of D
, that is, MSVC complains about C
being private.
My questions are:
- Am I right (and so is ICC) in my analysis? Otherwise which other compiler is correct and why?
- Is the MSVC issue yet another incarnation of two-phase instantiation bug in msvc?
Update: Regarding GCC, this seems to be the bug reported in comment 8, here.