C++中友元类的访问边界究竟如何界定?
C++友元权限边界与模板/Concept访问问题
类型a将友元权限授予类型k,按预期,嵌套私有类型a::t应在k的作用域内完全可访问——这一点在k的静态成员函数k::f的requires子句中直接写typename T::t时得到验证,所有编译器都能通过成员访问检查。
但实际测试出现不一致:
- 将该类型要求替换为定义完全一致的concept
c时,MSVC拒绝通过,而Clang和GCC可以 - 使用
k作用域外的模板别名u(对应k内部的模板别名h)时,GCC和MSVC都拒绝,仅Clang通过
核心疑问:GCC和MSVC的拒绝行为是否符合C++标准?授予另一类的友元权限边界究竟是什么?
template<typename T> concept c = requires { typename T::t; }; template<typename T> using u = typename T::t; struct k { template<typename T> using h = typename T::t; template<typename T> requires requires { typename T::t; // 所有编译器都通过 typename h<T>; // 所有编译器都通过 requires c<T>; // Clang通过,GCC通过,MSVC拒绝 typename u<T>; // Clang通过,GCC拒绝,MSVC拒绝 } static constexpr bool f() { return true; } }; class a { friend struct k; struct t; }; static_assert(k::f<a>()); // Clang通过,GCC拒绝,MSVC拒绝
GCC错误信息
<source>:23:22: 错误:找不到匹配的‘k::f<a>()’调用 23 | static_assert(k::f<a>()); | ~~~~~~~^~ <source>:17:29: 备注:候选函数:‘template<class T> requires requires{typename T::t;typename T::t;requires c<T>;typename T::t;} static constexpr bool k::f()’ 17 | } static constexpr bool f() { return true; } | ^ <source>:17:29: 备注:模板实参推导/替换失败: <source>:17:29: 备注:约束未满足 <source>: 在替换‘template<class T> requires requires{typename T::t;typename T::t;requires c<T>;typename T::t;} static constexpr bool k::f() [with T = a]’时: <source>:23:22: 需从此处调用 23 | static_assert(k::f<a>()); | ~~~~~~~^~ <source>:17:29: 受‘template<class T> requires requires{typename T::t;typename T::t;requires c<T>;typename T::t;} static constexpr bool k::f()’的约束要求 <source>:12:14: 在要求中 [with T = a] <source>:16:18: 备注:所需类型‘u<T>’无效,原因是 16 | typename u<T>; | ~~~~~~~~~^~~~~ <source>: 在替换‘template<class T> using u = typename T::t [with T = a]’时: <source>:5:7: 递归要求替换‘template<class T> using u = typename T::t [with T = a]’ 5 | using u = typename T::t; | ^ <source>:5:7: 要求替换‘template<class T> using u = typename T::t [with T = a]’ <source>:16:18: 要求替换‘template<class T> requires requires{typename T::t;typename T::t;requires c<T>;typename T::t;} static constexpr bool k::f() [with T = a]’ 16 | typename u<T>; | ~~~~~~~~~^~~~~ <source>:23:22: 需从此处调用 23 | static_assert(k::f<a>()); | ~~~~~~~^~ <source>:5:7: 致命错误:模板实例化深度超过最大值900 (使用‘-ftemplate-depth=’可增大最大值) 5 | using u = typename T::t; | ^
MSVC错误信息
<source>(23): 错误 C2672: ‘k::f’: 找不到匹配的重载函数 <source>(17): 备注:可能是‘bool k::f(void)’ <source>(23): 备注:关联约束未满足 <source>(15): 备注:concept‘c<a>’评估为false <source>(2): 备注:‘a::t’: 无法访问类‘a’中声明的私有struct <source>(21): 备注:参见‘a::t’的声明 <source>(19): 备注:参见‘a’的声明
内容的提问来源于stack exchange,提问作者303
相关产品推荐
相关产品推荐

