在非模板化函数中尾随require子句的编译器差异



考虑以下示例:

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()调用的候选;演示)。

  • 哪个编译器在这里是正确的,什么是(/are)相关的标准规则(/s)管理这个?

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

除非另有说明,否则以下所有标准参考均参考N4861(2020年3月布拉格后工作草案/c++ 20 DIS)。


这是Clang的错误,根据[dcl.decl]/4(以及[temp. construct .decl]/1), GCC拒绝该程序是正确的[强调我:

初始化声明器或中的可选require子句member-declarator只能在声明器声明模板化函数时出现。([dcl.fct])。当在声明者之后出现时,requires子句被称为后面的requires子句。[…]

同一段还包含一个(非规范的)例子,明确指出OP的例子是错误的:

(例子:

void f1(int a) requires true;       // error: non-templated function
template<typename T>
auto f2(T a) -> bool requires true; // OK
// ...

-结束示例]

我们可以注意到,在早期版本的N4810(将成为c++ 20)工作草案中,[dcl.decl]/4对允许出现require子句的地方有一个较弱的要求:

init-declaratormember-declarator中可选的require子句(第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 << "truen"; }
void f() requires (!B) { std::cout << "falsen"; }
};
int main() { 
S<true>{}.f();   // true
S<false>{}.f();  // false
} 

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


Clang bug报告:

  • Bug 48870 - accept -invalid for requirements -clause on non-template function

相关内容

  • 没有找到相关文章

最新更新