(特别是显式)特化中模板参数列表的访问检查规则

Access checking rules for template argument list in (particularly explicit) specializations

以下所有标准参考均指N4659: March 2017 post-Kona working draft/C++17 DIS


考虑以下 class 模板 A 和 class B,其中 private 定义了嵌套的 class C 和枚举 class E:

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

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

根据[temp.explicit]/12

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

我们可以参考例如指定显式实例化时模板参数列表中的私有类型,例如 B::CB::E

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

我正在尝试在标准中找到类似的部分,该部分指定在为(部分且特别是 explicit/full)专业化指定模板参数列表时是否同样放弃访问权限限制。

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

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

部分特化无法在 Clang 中编译

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

而 GCC 接受它。这可能是由于 GCC 和 Clang 之间的不同实例化规则。 GCC 和 Clang 都接受显式(/完全)专业化。

我怀疑显式(/完全)特化是良构的,而部分特化是错误的(隐含地由于默认规则)。但是,对于前者,我一直没能在[temp.expl.spec].

中找到类似[temp.explicit]/12的说法

问题

这里的规则在 C++17 完成后不久被 P0692 更改了,将当时的 [temp.explicit]/14 替换为 [temp.class.spec]/10 C++20 中的(对于部分特化)和 [temp.spec]/6(对于显式特化和实例化)。该论文提到它(在很大程度上)标准化了现有实践,因此一些编译器(继续)允许它甚至在以前的语言模式中也不足为奇。


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