GCC 接受此代码,Clang 和 MSVC 由于
assert
中静态断言失败而拒绝它。
标准怎么说?
https://godbolt.org/z/PKMKzYGsc
template<typename T>
constexpr int assert() {
static_assert(sizeof(T) == 1);
return 1;
}
template<auto I>
using Int = int;
template<typename T> requires (sizeof(T) == 1)
constexpr auto foo(T) -> Int<assert<T>()> {
return 1;
}
template<typename T> requires (sizeof(T) > 1)
constexpr auto foo(T a) -> Int<1> {
return 2;
}
static_assert(foo('1') == 1);
static_assert(foo(2) == 2);
Clang 输出:
<source>:3:19: error: static assertion failed due to requirement 'sizeof(int) == 1'
3 | static_assert(sizeof(T) == 1);
| ^~~~~~~~~~~~~~
<source>:11:30: note: in instantiation of function template specialization 'assert<int>' requested here
11 | constexpr auto foo(T) -> Int<assert<T>()> {
| ^
<source>:21:15: note: while substituting deduced template arguments into function template 'foo' [with T = int]
21 | static_assert(foo(2) == 2);
| ^
<source>:3:29: note: expression evaluates to '4 == 1'
3 | static_assert(sizeof(T) == 1);
该程序是格式良好,并且 gcc 正确接受代码,如下所述。
来自 over.over:
所有具有不满足关联约束的函数 ([temp.constr.decl]) 都会从所选函数集中消除。 如果该集合中保留了多个函数,并且该集合还包含不是函数模板特化的函数,则该集合中的所有函数模板特化都将被消除。 如果集合包含根据 [temp.constr.order] 的部分排序规则比 F0 受到更多约束的第二个非模板函数,则消除任何给定的非模板函数 F0。 如果集合包含第二个函数模板特化,根据 [temp.func.order] 的部分排序规则,其函数模板比 F1 的函数模板更特化,则消除任何给定的函数模板特化 F1。 在这样的消除之后,如果有的话,将仅保留一个选定的功能。
(强调我的)
这意味着对于调用
foo(2)
,带有 #1
的版本 sizeof(T)==1
将从所选函数集中删除。满足约束的另一个(版本#2
)将是唯一可行的候选者并被使用。