放弃 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:
问题
- 这里 C++20 中的正确行为是什么,上面的程序是否格式正确(GCC 错误/Clang 未完全实现)或者 GCC 和 Clang 是否正确拒绝它?
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))。
错误报告:
- 海湾合作委员会(确认):[C++20][P0692R1] Access checking not waived for declarations of explicit specializations of function and variable templates
- 叮当声:[P0692R1] Access checking not waived for declarations of explicit specializations of function and variable templates
(1) 请注意,Clang(如 OP 中突出显示的那样)已将 P0692R1 的实施状态标记为“部分”,因此这可能不是 Clang 错误,而是一项尚未完成的功能实现了 C++2a/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:
问题
- 这里 C++20 中的正确行为是什么,上面的程序是否格式正确(GCC 错误/Clang 未完全实现)或者 GCC 和 Clang 是否正确拒绝它?
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))。
错误报告:
- 海湾合作委员会(确认):[C++20][P0692R1] Access checking not waived for declarations of explicit specializations of function and variable templates
- 叮当声:[P0692R1] Access checking not waived for declarations of explicit specializations of function and variable templates
(1) 请注意,Clang(如 OP 中突出显示的那样)已将 P0692R1 的实施状态标记为“部分”,因此这可能不是 Clang 错误,而是一项尚未完成的功能实现了 C++2a/C++20.