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

C++20中decl-reachable是什么?相关示例疑问解析

C++20中的decl-reachable是什么?

C++20中的decl-reachable(声明可达)是模块系统里用来判定哪些声明会被保留在模块接口作用域中的核心规则,标准§10.4/3详细列出了所有判定情形,但理解起来有难度。下面结合§10.4/6中的示例来拆解核心问题:

源文件foo.h

namespace N { 
    struct X {}; 
    int d(); 
    int e(); 
    inline int f(X, int = d()) { return e(); } 
    int g(X); 
    int h(X); 
}

模块M接口

module; 
#include "foo.h" 
export module M; 

template<typename T> int use_f() { 
    N::X x; // N::X、N以及全局作用域可从use_f进行decl-reachable
    return f(x, 123); // N::f可从use_f进行decl-reachable,
                      // N::e可间接从use_f进行decl-reachable
                      // 因为它可从N::f进行decl-reachable,并且
                      // N::d可从use_f进行decl-reachable
                      // 因为它可从N::f进行decl-reachable
                      // 即使在此调用中未被使用
} 

template<typename T> int use_g() { 
    N::X x; // N::X、N以及全局作用域可从use_g进行decl-reachable
    return g((T(), x)); // N::g不可从use_g进行decl-reachable
} 

template<typename T> int use_h() { 
    N::X x; // N::X、N以及全局作用域可从use_h进行decl-reachable
    return h((T(), x)); // N::h不可从use_h进行decl-reachable,但
                        // N::h可从use_h<int>进行decl-reachable
} 

int k = use_h<int>(); // use_h<int>可从k进行decl-reachable,因此
                      // N::h可从k进行decl-reachable

模块M实现

module M; 

int a = use_f<int>(); // 合法
int b = use_g<int>(); // 错误:无匹配的g调用函数;
                      // g不可从模块M接口的作用域进行decl-reachable,因此被丢弃
int c = use_h<int>(); // 合法

问题解答

1. 为什么N::g不可从use_g进行decl-reachable?

在use_g的模板定义阶段(未实例化时),调用g((T(), x))的参数(T(), x)是依赖模板参数T的表达式。此时编译器无法确定T()的具体类型,也就没法确认这个逗号表达式的结果是否能隐式转换为N::g要求的N::X类型。根据decl-reachable规则,只有能在模板定义阶段确定会被有效使用的声明,才会被标记为可达。由于这里的函数调用有效性依赖未确定的模板参数,编译器无法认定N::g是该模板的必要依赖,因此不会标记它从use_g可达。

2. 为什么N::h不可从use_h进行decl-reachable,但可从use_h<int>进行decl-reachable?

  • 对于未实例化的模板use_h,情况和use_g完全一致:参数(T(), x)的类型依赖T,编译器无法在模板定义阶段确认这个参数能匹配N::h的N::X参数,因此N::h不可从use_h(模板本身)可达。
  • 当模板被实例化为use_h<int>时,T()就是int(),结果为int类型,而逗号表达式(int(), x)的最终结果是x(类型N::X),此时编译器能明确这个参数完全匹配N::h的参数要求,函数调用是有效的。因此在实例化后的use_h<int>中,N::h会被标记为可达。

3. 为什么§10.4/(3.2)或§10.4/(3.3)不适用于它们?

§10.4/(3.2)的规则是:若一个声明是某个可达声明的潜在重载候选,则它是可达的;§10.4/(3.3)是:若一个声明是某个可达声明的依赖于参数的查找(ADL)候选,则它是可达的。
对于未实例化的use_g和use_h,由于调用的参数类型依赖模板参数,编译器在模板定义阶段无法确定N::g/N::h是否属于该调用的合法重载候选——连参数类型都不确定,自然没法判定重载匹配关系。因此这两条规则都无法触发。只有当模板实例化后,参数类型明确,编译器才能确认它们是合法的重载候选,此时相关规则才会生效,标记N::h从use_h<int>可达。

内容的提问来源于stack exchange,提问作者YZ_SO

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 00:20:28