放弃 C++20 中显式函数模板特化的访问检查规则

Waiving of access checking rules for explicit function template specializations in C++20

[temp.spec]/6 was added to C++20 by implementation of P0692R1专业化访问检查)[强调我的]:

[temp.spec]/6 The usual access checking rules do not apply to names in a declaration of an explicit instantiation or explicit specialization, with the exception of names appearing in a function body, default argument, base-clause, member-specification, enumerator-list, or static data member or variable template initializer. [ Note: In particular, the template arguments and names used in the function declarator (including parameter types, return types and exception specifications) may be private types or objects that would normally not be accessible. — end note ]

afaict 将使以下程序在 C++20 中成为良构的:

class A { class B {}; };

template<typename T> void foo() {};
template<> void foo<A::B>() {}

int main() {}

但是,两个 GCC (HEAD 11.0.0 20201121; DEMO) and Clang (HEAD 12.0.0; DEMO) 都拒绝上面的程序 (for -std=c++20/-std=c++2a) , 引用私人访问违规

GCC:

'class A::B' is private within this context

Clang:

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

GCC 将 P0692R1 列为已实现:

而 Clang 将 P0692R1 的实现列为 Partial:

问题

What is the correct behaviour in C++20 here, is the program above well-formed (GCC bug / Clang not fully implemented) or are GCC and Clang correct to reject it?

正如 OP 中已经引用的那样,[temp.spec]/6 支持此功能,并且程序格式正确。特别是,下面的所有片段 (A) 到 (D) 都是格式正确的:

// (A)
class A { class B {}; };
 
template<typename T> struct S {};
template<> struct S<A::B> {};

// (B)
class A { class B {}; };
 
template<typename T> void foo() {};
template<> void foo<A::B>() {}
 
// (C)
class A { class B {}; };
 
template<typename T>
constexpr bool v = false;

template<>
constexpr bool v<A::B> = true;

// (D)
class A { class B {}; };

template<typename T, typename U> struct S {};
template<typename U> struct S<A::B, U> {};
template<typename T> struct S<T, A::B> {};

GCC错误的拒绝(B)和(C)(正确接受(A)和(D)),Clang错误的(1)拒绝(B ) 到 (D)(正确接受 (A))。

错误报告:

(1) 请注意,Clang(如 OP 中突出显示的那样)已将 P0692R1 的实施状态标记为“部分”,因此这可能不是 Clang 错误,而是一项尚未完成的功能实现了 C++2a/C++20.