C++中重载决议如何从多个潜在析构函数中选定类的目标析构函数?
C++中重载决议如何从多个潜在析构函数中选定类的目标析构函数?
这个问题抓得非常准!很多人刚接触C++20的约束析构函数时都会有这个困惑,咱们从你提到的Optional例子入手,一步步把规则讲清楚:
先拆解你的Optional案例
首先看这段代码:
template<typename T> class Optional { public: ~Optional() requires (!std::is_trivially_destructible_v<T>); ~Optional() = default; };
看起来两个析构函数会冲突,但实际上C++20的重载决议规则专门处理了这种带约束函数和无约束函数的优先级问题,根本不会出现“两个 viable 析构函数”导致编译失败的情况。
第一步:筛选候选析构函数
当类定义完成后,编译器会对所有潜在析构函数做两件事:
- 完成模板参数的替换(针对模板类的情况);
- 检查每个析构函数的
requires约束是否满足。
不满足约束的析构函数会直接被踢出候选集,完全不参与后续的重载决议:
- 如果
T是平凡可析构类型(比如int、float),第一个析构函数的requires条件不成立,会被排除,剩下的只有默认析构函数,直接选中它; - 如果
T是非平凡可析构类型(比如std::string、自定义带非默认析构的类),第一个析构函数的约束满足,会进入候选集;同时第二个默认析构函数因为没有约束(等价于约束永远为true),也会进入候选集。
第二步:重载决议的优先级排序
这时候两个候选析构函数都是无参数的,怎么选?关键就在C++对于约束函数的重载排序规则:
当两个可行函数都符合要求时,带约束且约束更严格的函数会被优先选中。不带约束的函数相当于拥有一个“永远为true”的默认约束,而带具体条件的约束显然比这个默认约束更严格(因为满足前者的情况是后者的子集)。
在Optional的例子里,第一个析构函数的约束!std::is_trivially_destructible_v<T>是第二个析构函数“无约束”的子集——只有当T是非平凡可析构时,第一个约束才成立,而第二个约束(默认)始终成立。所以编译器会优先选中第一个析构函数,不会出现冲突。
潜在析构函数的重载决议通用流程
把上面的逻辑提炼成通用规则:
- 筛选候选集:对每个潜在析构函数,替换模板参数后检查
requires约束,只保留约束满足的(无约束的默认保留); - 选出最优函数:在候选集中,按照约束严格性、函数匹配规则排序,选出唯一的最优函数作为类的选定析构函数;
- 非法情况:如果候选集为空,或者有多个无法分出优先级的最优函数(比如两个约束互不蕴涵的析构函数),程序就是非法的(ill-formed)。
你之前看到的“如果解析到多个析构函数,代码就是非法的”说法是对的,但前提是这些析构函数在重载决议中无法分出优先级——而Optional的例子恰好避开了这个情况,因为两个析构函数的约束有明确的优先级关系。
内容来源于stack exchange
相关产品推荐
相关产品推荐

