C++中IFNDR与约束子归纳:重载决议歧义还是IFNDR?
C++模板约束:IFNDR与重载决议分析
标准中的IFNDR案例
C++标准里有这么一个例子,因为违反「功能等价但词法不等价」规则,被判定为IFNDR(无需诊断的非法程序):
template <unsigned N> constexpr bool Atomic = true; template <unsigned N> concept C = Atomic<N>; template <unsigned N> concept Add1 = C<N + 1>; template <unsigned N> void f2() requires Add1<2 * N>; template <unsigned N> int f2() requires Add1<N * 2> && true; void h2() { f2<0>(); // 非法,无需诊断: // 需要判断功能等价但词法不等价的原子约束之间的包含关系 }
案例解析
这个例子里,两个模板的约束经过归一化后,得到原子约束Atomic<2 * N + 1>和Atomic<N * 2 + 1>。这两个约束来自同一个词法表达式(都是Add1概念展开后的Atomic<...>),所以要按照标准[temp.constr.atomic]/2条款检查等价性。虽然它们功能上完全等价(计算结果始终一致),但词法结构不同,因此程序被判定为IFNDR。
自定义场景的问题解答
场景代码
template <class T> inline constexpr bool trait1_v = /* ... */; template <class T> inline constexpr bool trait2_v = /* ... */; namespace ns1 { template <class T> void foo(T) requires trait1_v<T> {} } namespace ns2 { template <class T> void foo(T) requires trait1_v<T> && trait2_v<T> {} }
核心结论
当通过ADL找到这两个foo重载并触发约束偏序检查时:
- 不会触发IFNDR相关的等价性检查:两处的
trait1_v<T>是独立的词法表达式(分别在两个命名空间的函数模板requires子句中),不满足标准中触发等价性判定的前提——只有当原子约束来自同一词法表达式时,才会进行功能等价性的检查。因此不会出现IFNDR的情况。 - 不会产生重载决议歧义:约束偏序会明确区分两个重载的优先级:
- 如果调用时
trait2_v<T>为true,ns2::foo的约束trait1_v<T> && trait2_v<T>比ns1::foo的trait1_v<T>更严格(前者蕴含后者),因此ns2::foo会被选为更合适的重载; - 如果
trait2_v<T>为false,则只有ns1::foo满足约束条件,会被选中。
- 如果调用时
内容的提问来源于stack exchange,提问作者Brian Bi
相关产品推荐
相关产品推荐

