c++ 与归类有关的“功能等同但不等同”的含义

68bkxrlz  于 2023-03-14  发布在  其他
关注(0)|答案(1)|浏览(128)

以下来自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?

7bsow1i6

7bsow1i61#

[temp.over.link]/7说:

如果程序的有效性或意义依赖于两个构造是否等价,并且它们在功能上等价但不等价,则程序是病态的,不需要诊断。

在这种情况下,两个原子约束由不同的表达式形成,并且无论其参数Map的(功能)等效性如何都不相同。因此,后者不会影响此程序的有效性或意义,并且[temp.over.link]/7不适用。是否实际执行模板测试并不重要。
(Also在该特定示例中,出现在程序中的所有三个原子约束的参数Map无论如何都是等价的。

相关问题