6
votes

All standard references below refers to N4659: March 2017 post-Kona working draft/C++17 DIS.


Consider the following class template A and class B which private defines a nested class C and enum class E:

template<typename T, typename U>
class A {};

class B { 
    class C {};
    enum class E {};
};

According to [temp.explicit]/12:

The usual access checking rules do not apply to names used to specify explicit instantiations. [...]

we may refer e.g. to private types such as B::C and B::E in the template argument list when specifying explicit instantiations:

// OK: explicit instantiation definition.
template class A<B::C, B::E>;

I'm trying to find the similar segment in the standard that specifies whether the same waiving of access right restrictions when specifying the template argument list for (partial and particularly explicit/full) specializations.

// Partial specialization.
template<typename U>
class A<B::C, U> {};

// Explicit(/full) specialization.
template<>
class A<B::C, B::E> {};

The partial specialization fails to compile in Clang

error: 'C' is a private member of 'B'

whereas GCC accepts it. Possibly this is due to different instantiation rules between GCC and Clang. Both GCC and Clang accepts the explicit(/full) specialization.

I'm suspecting the explicit(/full) specialization is well-formed whereas the partial specialization is ill-formed (implicitly due to default rules). However, for the former, I have not been able to find a statement similar to that of [temp.explicit]/12 in [temp.expl.spec].

Question

  • Where, in the standard, is it specified (implicitly or explicitly) that the usual access checking rules do not apply for the template argument list for (particularly explicit/full) specializations?
1
There’s no such thing as a “partial explicit specialization”, just “partial specializations” and “explicit specializations” (sometimes called “full specializations”).Davis Herring
@DavisHerring You're right, thanks ([temp.spec]/3: An explicit specialization declaration is introduced by template<>). I've will update the wording of the question accordingly. Do you happen to also know the answer, whether we may or may not legally waive access checking rules for explicit(/full) specializations?dfrib

1 Answers

4
votes

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. [...]