You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.16 16:08:14