All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.
Consider the following class template A
The rule here was changed shortly after C++17 was finished by P0692, replacing what was then [temp.explicit]/14 with what is [temp.class.spec]/10 (for partial specializations) and [temp.spec]/6 (for explicit specializations and instantiations) in C++20. The paper mentions that it was (largely) standardizing existing practice, so it’s not surprising that some compilers (continue to) allow it even in prior language modes.
Access Checking on Specializations
Abstract
This paper attempts to address a long-standing hole in the ability for developers to specialize templates on their private and protected nested class-types. It also identifies an implementation divergence between compilers.
Abstract Code Example
To be clear about what is being discussed, the following code is a minimal example:
template<class T> struct trait; class class_ { class impl; }; // Not allowed in standard C++ (impl is private) template<> struct trait<class_::impl>;
It is important to note that even though the above specialization of trait is not allowed according to the standard, it builds with all compilers that were tested, including various versions of gcc, clang, icc, and msvc. Already, for the sake of standardizing existing practice, one might argue that this should be allowed. [...]