【问题标题】:Compiler variance for trailing requires-clauses on non-templated functions非模板函数的尾随要求子句的编译器差异
【发布时间】:2021-04-29 03:35:46
【问题描述】:

考虑以下示例:

void f() requires true { }
int main() { f(); }

Clang(1) (DEMO) 接受这个程序,而 GCC(1) (DEMO) 拒绝它并出现以下错误:

error: constraints on a non-templated function

请注意,约束表达式实际上可以用于 Clang 的情况,因为以下程序被 Clang 拒绝:

void f() requires false { }
int main() { f(); }  //  // error: no matching function for call to 'f'

Clang 指出声明的 f 不是候选对象,因为不满足约束条件(因为它是 f() 调用的候选对象;DEMO)。

  • 此处哪个编译器是正确的,管理此问题的相关标准规则是什么?

(1) GCC HEAD 11.0.0 20210124 和 Clang HEAD 12.0.0 (20210124),-std=c++20.

【问题讨论】:

  • 我个人觉得它们很有趣;我希望您继续发布此类问答。

标签: c++ gcc clang language-lawyer c++20


【解决方案1】:

除非另有说明,否则以下所有标准参考均指N4861 (March 2020 post-Prague working draft/C++20 DIS)


这是一个 Clang 错误,根据 [dcl.decl]/4(以及 [temp.constr.decl]/1),GCC 拒绝该程序是正确的 [emphasis mine]:

init-declarator 中的可选 requires-clausemember-declarator 只有在声明器声明了一个模板化函数时才会出现 ([dcl.fct])。在声明符之后出现时, requires-clause 被称为 trailing requires-clause。 [...]

同一段落还包含一个(非规范性)示例,明确指出 OP 的示例格式错误:

[ 例子:

void f1(int a) requires true;       // error: non-templated function

template<typename T>
auto f2(T a) -> bool requires true; // OK

// ...

结束示例 ]

我们可能会注意到,在(成为 C++20)工作草案的早期版本中,N4810, [dcl.decl]/4 对允许出现要求子句的位置的要求较弱:

init-declaratormember-declarator 中的可选 requires-clause(第 13 条)在声明符执行时不应出现不声明函数(9.2.3.5)。 [...]

[ 例子:

void f1(int a) requires true; // OK

// ...

结束示例 ]

其中 OP 用例的非规范示例被明确显示为格式正确。可以说,最初的意图是允许基于类模板的模板参数来约束类模板的非模板成员函数:

#include <iostream>

template<bool B>
struct S {
    void f() requires   B  { std::cout << "true\n"; }
    void f() requires (!B) { std::cout << "false\n"; }
};

int main() { 
    S<true>{}.f();   // true
    S<false>{}.f();  // false
} 

在 N4861 中 [dcl.decl]/4 的最终状态(用于 C++20)中仍然允许这样做,其中限制是对 模板函数 的限制(参见 templated entity in [temp.pre]/8,尤其是[temp.pre]/8.3),不仅涵盖函数模板(以及非模板的函数模板成员和模板类模板),还包括类的非模板成员函数模板。


Clang 错误报告:

【讨论】:

  • 很好的作品展示了文本在版本之间是如何变化的,以及原始文本背后的意图和变化。
  • 显着变化。我记得放宽了 C++11 的 typename 要求,现在它也可以用于模板之外的嵌套名称。没有必要这样做,但它简化了规则。
  • @MSalters 请注意,此限制更改仅适用于 C++20 之前不存在的功能,因此这些更改仅适用于工作草案。不过,Imo 对于受约束的非模板友元函数的规则仍有一些不明确之处,我强调了这方面的一些编译器差异(极端情况)in the following Q&A
猜你喜欢
  • 2021-12-30
  • 1970-01-01
  • 2021-04-23
  • 1970-01-01
  • 2021-07-25
  • 1970-01-01
  • 2020-11-29
  • 1970-01-01
  • 2022-11-25
相关资源
最近更新 更多