当不满足前导约束时,从返回类型触发静态断言

问题描述 投票:0回答:1

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);
c++ language-lawyer c++20 c++-concepts
1个回答
0
投票

该程序是格式良好,并且 gcc 正确接受代码,如下所述。

来自 over.over:

所有具有不满足关联约束的函数 ([temp.constr.decl]) 都会从所选函数集中消除。 如果该集合中保留了多个函数,并且该集合还包含不是函数模板特化的函数,则该集合中的所有函数模板特化都将被消除。 如果集合包含根据 [temp.constr.order] 的部分排序规则比 F0 受到更多约束的第二个非模板函数,则消除任何给定的非模板函数 F0。 如果集合包含第二个函数模板特化,根据 [temp.func.order] 的部分排序规则,其函数模板比 F1 的函数模板更特化,则消除任何给定的函数模板特化 F1。 在这样的消除之后,如果有的话,将仅保留一个选定的功能。

(强调我的)

这意味着对于调用

foo(2)
,带有
#1
的版本
sizeof(T)==1
将从所选函数集中删除。满足约束的另一个(版本
#2
)将是唯一可行的候选者并被使用。

© www.soinside.com 2019 - 2024. All rights reserved.