非模板函数尾随要求子句的编译器差异
Compiler variance for trailing requires-clauses on non-templated functions
考虑以下示例:
void f() requires true { }
int main() { f(); }
Clang(1) (DEMO) accepts this program, whereas 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'
with Clang 注意到声明的 f
不是候选者,因为不满足约束(因为它是 f()
调用的候选者;DEMO)。
- 这里哪个编译器是正确的,管理它的相关标准规则是什么?
(1) GCC HEAD 11.0.0 20210124 和 Clang HEAD 12.0.0 (20210124),-std=c++20
.
除非另有说明,否则以下所有标准参考文献均指 N4861 (March 2020 post-Prague working draft/C++20 DIS)。
这是一个 Clang 错误,GCC 拒绝该程序是正确的,根据 [dcl.decl]/4 (as well as [temp.constr.decl]/1) [强调 我的]:
The optional requires-clause in an init-declarator or
member-declarator shall be present only if the declarator declares a templated function ([dcl.fct]). When present after a declarator,
the requires-clause is called the trailing requires-clause. [...]
同一段落还包含一个(非规范的)示例,明确指出 OP 的示例格式不正确:
[ Example:
void f1(int a) requires true; // error: non-templated function
template<typename T>
auto f2(T a) -> bool requires true; // OK
// ...
— end example ]
我们可能会注意到,在(成为 C++20 的)工作草案的早期版本中,N4810、[dcl.decl]/4 对 where requires-clauses 的要求较弱被允许出现:
The optional requires-clause (Clause 13) in an init-declarator or member-declarator shall not be present when the declarator does not declare a function (9.2.3.5). [...]
[ Example:
void f1(int a) requires true; // OK
// ...
— end example ]
其中 OP 用例的非规范示例明确显示为格式正确。最初的意图可以说是允许根据 class 模板的模板参数来约束 class 模板的非模板成员函数:
#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)仍然允许这样做,其中限制是 模板函数(参见[temp.pre]/8, particularly [temp.pre]/8.3中的templated entity),它不仅仅涵盖函数模板(以及非模板和模板的函数模板成员class模板),还有 class 个模板的非模板成员函数。
Clang 错误报告:
考虑以下示例:
void f() requires true { }
int main() { f(); }
Clang(1) (DEMO) accepts this program, whereas 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'
with Clang 注意到声明的 f
不是候选者,因为不满足约束(因为它是 f()
调用的候选者;DEMO)。
- 这里哪个编译器是正确的,管理它的相关标准规则是什么?
(1) GCC HEAD 11.0.0 20210124 和 Clang HEAD 12.0.0 (20210124),-std=c++20
.
除非另有说明,否则以下所有标准参考文献均指 N4861 (March 2020 post-Prague working draft/C++20 DIS)。
这是一个 Clang 错误,GCC 拒绝该程序是正确的,根据 [dcl.decl]/4 (as well as [temp.constr.decl]/1) [强调 我的]:
The optional requires-clause in an init-declarator or member-declarator shall be present only if the declarator declares a templated function ([dcl.fct]). When present after a declarator, the requires-clause is called the trailing requires-clause. [...]
同一段落还包含一个(非规范的)示例,明确指出 OP 的示例格式不正确:
[ Example:
void f1(int a) requires true; // error: non-templated function template<typename T> auto f2(T a) -> bool requires true; // OK // ...
— end example ]
我们可能会注意到,在(成为 C++20 的)工作草案的早期版本中,N4810、[dcl.decl]/4 对 where requires-clauses 的要求较弱被允许出现:
The optional requires-clause (Clause 13) in an init-declarator or member-declarator shall not be present when the declarator does not declare a function (9.2.3.5). [...]
[ Example:
void f1(int a) requires true; // OK // ...
— end example ]
其中 OP 用例的非规范示例明确显示为格式正确。最初的意图可以说是允许根据 class 模板的模板参数来约束 class 模板的非模板成员函数:
#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)仍然允许这样做,其中限制是 模板函数(参见[temp.pre]/8, particularly [temp.pre]/8.3中的templated entity),它不仅仅涵盖函数模板(以及非模板和模板的函数模板成员class模板),还有 class 个模板的非模板成员函数。
Clang 错误报告: