以下是基于Richard Smith的answer到Is is_constexpr possible in 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_1
和is_constexpr_2
均无效,因为它们违反了通常的规则,即函数参数不可在常量表达式中使用。它们分别需要x
和f
,至少有时可以用作常量表达式,而从不使用。
在这种情况下,[expr.const]/4限制为:
没关系,其他两个项目符号是什么,因为我们在引用变量的id表达式上没有预先进行的初始化。
正如Richard Smith在linked answer中解释的那样,is_constexpr_3
是有效的。
我的期望是:
|
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
这是lang所做的。
关于c++ - 尝试实现is_constexpr()-编译器不同,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56243158/