尝试实现IS_CONSTEXPR() - 编译器差异

Attempt to implement is_constexpr() - compilers diverge

本文关键字:编译器 CONSTEXPR 实现 IS      更新时间:2023-10-16

以下是基于理查德·史密斯(Richard Smith(对IS_Constexpr的答案在C 11中实现is_constexpr()的三次尝试?

版本1

template <typename T>
bool constexpr is_constexpr_impl_1(const T& x, decltype(int{(x, 0u)})) { return true; }
template <typename T>
bool constexpr is_constexpr_impl_1(const T&, ...) { return false; }
template <typename T>
bool constexpr is_constexpr_1(const T& x) { return is_constexpr_impl_1(x, 0); }

版本2

template <typename T>
bool constexpr is_constexpr_impl_2(const T& f, decltype(int{(f(0), 0u)})) { return true; }
template <typename T>
bool constexpr is_constexpr_impl_2(const T&, ...) { return false; }
template <typename T>
bool constexpr is_constexpr_2(const T& f) { return is_constexpr_impl_2(f, 0); }

版本3

template <auto f>
bool constexpr is_constexpr_impl_3(decltype(int{(f(0), 0u)})) { return true; }
template <auto f>
bool constexpr is_constexpr_impl_3(...) { return false; }
template <auto f>
bool constexpr is_constexpr_3() { return is_constexpr_impl_3<f>(0); }

我已经用GCC 9.1,Clang 8.0.0,ICC 19.0.1和MSVC 19.20测试了以上(请参阅Godbolt(,以及以下功能的帮助:

void constexpr f_c(int) {}
void f_nc(int) {}

下表显示了我在static_assert中放置的表达式。我希望所有人都通过,但编译器不同意我和之间的意见(ICC和MSVC彼此一致(:

                        | gcc  | clang | icc  | msvc |
 is_constexpr_1(0)      | pass | fail  | pass | pass |
 is_constexpr_2(f_c)    | fail | fail  | pass | pass |
!is_constexpr_2(f_nc)   | pass | pass  | fail | fail |
 is_constexpr_3<f_c>()  | pass | pass  | pass | pass |
!is_constexpr_3<f_nc>() | pass | pass  | fail | fail |

谁是对的,为什么?(标准的报价将很有用。(

is_constexpr_1is_constexpr_2都不是有效的,因为它们符合通常的规则,即功能参数在常数表达式中不可用。它们分别需要xf至少有时可作为恒定表达式使用,而它们从来没有。

在这种情况下,[expr.const]/4的限制:

AN id-expression 是指参考类型的变量或数据成员

其他两个子弹是什么都没有关系,因为我们在 id-expression 上没有提到变量的初始化。

is_constexpr_3是有效的,正如理查德·史密斯(Richard Smith(在链接的答案中解释的那样。

我的期望是:

                        | 
 is_constexpr_1(0)      | fail
 is_constexpr_2(f_c)    | fail
!is_constexpr_2(f_nc)   | pass
 is_constexpr_3<f_c>()  | pass
!is_constexpr_3<f_nc>() | pass

Clang的作用。