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

dfr*_*fri 6 c++ templates template-specialization language-lawyer

以下所有标准参考均指N4659:2017 年 3 月后 Kona 工作草案/C++17 DIS


考虑以下类模板A和类B,其私有定义了嵌套类C和枚举类E

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

class B { 
    class C {};
    enum class E {};
};
Run Code Online (Sandbox Code Playgroud)

根据[temp.explicit]/12

通常的访问检查规则不适用于用于指定显式实例化的名称。[...]

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

// OK: explicit instantiation definition.
template class A<B::C, B::E>;
Run Code Online (Sandbox Code Playgroud)

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

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

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

部分专业化无法在 Clang 中编译

error: 'C' is a private member of 'B'
Run Code Online (Sandbox Code Playgroud)

而海湾合作委员会接受它。这可能是由于 GCC 和 Clang 之间的实例化规则不同。GCC 和 Clang 都接受显式(/完整)特化。

我怀疑显式(/完全)专业化是格式良好的,而部分专业化是格式错误的(隐式由于默认规则)。但是,对于前者,我一直没能在[temp.expl.spec] 中找到类似于[temp.explicit]/12语句

  • 在标准中,是否(隐式或显式)指定了通常的访问检查规则不适用于(特别是显式/完整)专业化的模板参数列表?

Dav*_*ing 4

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

\n
\n
\n

专业化访问检查

\n

抽象的

\n

本文试图解决开发人员在其私有和受保护的嵌套类类型上专门化模板的能力中长期存在的漏洞。它还识别编译器之间的实现差异。

\n

抽象代码示例

\n

为了清楚地说明所讨论的内容,以下代码是\n最小示例:

\n
template<class T>\nstruct trait;\n\nclass class_ {\n  class impl;\n};\n\n// Not allowed in standard C++ (impl is private)\ntemplate<>\nstruct trait<class_::impl>;\n
Run Code Online (Sandbox Code Playgroud)\n

需要注意的是,尽管根据标准不允许上述\ntrait 的特殊化,但它是使用所有经过测试的\n编译器构建的,包括各种版本的 gcc、clang、nicc 和 msvc。为了使现有实践标准化,人们可能会认为应该允许这样做。[...]

\n
\n