以下来自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>(); // ill-formed, no diagnostic required:
// requires determination of subsumption between atomic constraints that are
// functionally equivalent but not equivalent
}
看起来这里发生的事情是我们最终必须检查原子约束Atomic<2 * N + 1>
和Atomic<N * 2 + 1>
(通过将每个概念id用其模板自变量替换到概念的定义中的结果,即约束归一化,重复替换而形成)相同。如果这两个原子约束源自词汇上不同的表达式,则它们将不相同,但在本例中,从词汇上讲,它们源自单个表达式(* 即 * 出现在第二行末尾的“Atomic<N>
“),因此,在[temp.constr.atomic]/2下,我们必须检查A<2 * N + 1>
和A<N * 2 + 1>
是否等价,其中A
是一个假设模板,其声明可能类似于
template <unsigned N> class A;
由于这两个template-id在功能上等价但不等价,所以程序是病态的,不需要诊断。
这就引出了我真正关心的一个例子:
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> {}
}
假设程序包含对foo
的调用,这样ADL发现了两个foo
重载,并且约束的偏序开始起作用。我知道trait1_v<T>
的两次出现不会包含彼此,因为它们在词汇上不是相同的表达式。这是否意味着模板等价性测试永远不会起作用?因此我们从来没有遇到“功能等价但不等价”,所以我们只是得到了一个模糊的重载解决方案,而不是IFNDR?
1条答案
按热度按时间7bsow1i61#
[temp.over.link]/7说:
如果程序的有效性或意义依赖于两个构造是否等价,并且它们在功能上等价但不等价,则程序是病态的,不需要诊断。
在这种情况下,两个原子约束由不同的表达式形成,并且无论其参数Map的(功能)等效性如何都不相同。因此,后者不会影响此程序的有效性或意义,并且[temp.over.link]/7不适用。是否实际执行模板测试并不重要。
(Also在该特定示例中,出现在程序中的所有三个原子约束的参数Map无论如何都是等价的。