【问题标题】:Concept checks with invalid function calls succeed无效函数调用的概念检查成功
【发布时间】:2022-12-14 07:29:54
【问题描述】:

在定义 c++20 概念以检查是否通过调用约束函数满足要求时,g++ 和 clang 中的行为不同。如果检查函数无效,g++ 接受一个类型,clang 则相反:

// constrained function
template <class T>
constexpr void foo1(const T& type)
  requires requires { type.foo(); }{} 

// function with required expression in the body
template <class T>
constexpr auto foo2(const T& type)
  { type.foo(); }                       // (x)

// check for valid expression foo1
template <class T>
concept checkFoo1 = requires(T t) { foo1(t); };

// check for valid expression foo2
template <class T>
concept checkFoo2 = requires(T t) { foo2(t); };

检查没有 foo() 作为成员的类型的概念会给出不一致的行为:

struct Test 
{
  // void foo() const {}
};

int main()
{
  static_assert(checkFoo1<Test>);   // (1)
  static_assert(checkFoo2<Test>);   // (2)
  static_assert(!checkFoo1<Test>);  // (3)
  static_assert(!checkFoo2<Test>);  // (4)
}

在 clang-15 中:(1),(2): static assertion, (3),(4): succeed,另外 (x) 中的错误,参见https://godbolt.org/z/zh18rcKz7

g++-12: (1),(4): static assertion, (2),(3): succeed, additionally an error in (x), see https://godbolt.org/z/qMsa59nd3

在所有情况下,概念检查都不会在静态断言的错误消息中说明失败的原因,即未找到成员函数.foo()。它只是告诉您对foo1()foo2() 的调用无效。

我的问题是:

  • 什么是正确的行为,为什么?
  • 如何通过约束函数检查概念,以及有关为什么调用 foo1()foo2() 无效以及未满足这些函数的约束的详细信息。

当然,我可以直接检查成员函数foo() 是否存在。但这只是一个例子。目标是通过对受限函数的递归函数调用来模拟递归概念之类的东西。应用是:检查元组的所有元素是否满足某个概念,或检查类型树中所有节点的概念。

【问题讨论】:

  • 至少对于带有附加选项-fconcepts-diagnostics-depth=2的g++,我得到了为什么foo1()无效的信息。 clang 不显示此附加信息。

标签: c++ g++ clang c++20 c++-concepts


【解决方案1】:

使用无效类型调用/实例化 foo2 会产生硬错误,而不是替换错误(对 SFINAE 输出)。

所以 checkFoo2&lt;Test&gt; 使程序格式错误。

当编译器尝试继续给出更多错误时,他们会以某种方式处理错误,而在给定情况下这些方式并不相同。

两个编译器都是正确的。然后甚至正确地识别问题:

错误:“const struct Test”没有名为“foo”的成员。

但以下错误(来自上述错误)不一定相关/准确。

【讨论】:

  • 那么,实际上在 clang 中,static_assert (4) 没有成功,只是由于表达式内部的硬错误而没有被处理?但是在 (2) 中也应该发生硬错误,但静态断言仍然在处理和打印。在 gcc 中,这是相反的行为。如果表达式产生硬错误,可能是实现定义了 static_assert 中会发生什么。那么任何进一步的行为都是“正确的”。
  • 你大多有static_assert(HardErrorDetectedForCheckFoo2);。由编译器从中恢复以允许更多诊断。考虑到它是 falsetrue 是一种可能性,拒绝/接受 (2)/(4) 也是一种有效的可能性。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 1970-01-01
  • 2021-04-11
  • 2021-11-27
  • 2020-10-28
相关资源
最近更新 更多