【发布时间】:2021-06-26 09:04:42
【问题描述】:
看看下面的代码
#include <type_traits>
template <typename T>
struct basic_type {
using type = T;
};
consteval auto foo(auto p, auto x) noexcept {
if constexpr (p(x)) {
return 1;
} else {
return 0;
}
}
int main() {
// This compiles
return foo(
[]<typename T>(basic_type<T>)
{
return std::is_integral_v<T>;
},
basic_type<int>{});
// This gives "x is not a constant expression"
/*return foo(
[]<typename T>(T)
{
return std::is_integral_v<std::decay_t<T>>;
},
0);*/
}
第一个 return 语句在最新的 gcc 主干上编译得很好,而第二个没有编译,错误消息:
source>: In instantiation of 'consteval auto foo(auto:1, auto:2) [with auto:1 = main()::<lambda(T)>; auto:2 = int]':
<source>:26:12: required from here
<source>:9:3: error: 'x' is not a constant expression
9 | if constexpr (p(x)) {
| ^~
<source>: In function 'int main()':
<source>:26:19: error: 'consteval auto foo(auto:1, auto:2) [with auto:1 = main()::<lambda(T)>; auto:2 = int]' called in a constant expression
26 | return foo(
| ~~~^
27 | []<typename T>(T)
| ~~~~~~~~~~~~~~~~~
28 | {
| ~
29 | return std::is_integral_v<std::decay_t<T>>;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
30 | },
| ~~
31 | 0);
| ~~
<source>:8:16: note: 'consteval auto foo(auto:1, auto:2) [with auto:1 = main()::<lambda(T)>; auto:2 = int]' is not usable as a 'constexpr' function because:
8 | consteval auto foo(auto p, auto x) noexcept {
| ^~~
谁能告诉我为什么?
这是一个神螺栓链接 https://godbolt.org/z/71rbWob4e
编辑
根据要求,这里是没有自动参数的 foo:
template<typename Predicate, typename T>
consteval auto foo(Predicate p, T x) noexcept {
if constexpr (p(x)) {
return 1;
} else {
return 0;
}
}
错误信息如下所示:
<source>: In instantiation of 'consteval auto foo(Predicate, T) [with Predicate = main()::<lambda(T)>; T = int]':
<source>:27:15: required from here
<source>:10:3: error: 'x' is not a constant expression
10 | if constexpr (p(x)) {
| ^~
<source>: In function 'int main()':
<source>:27:15: error: 'consteval auto foo(Predicate, T) [with Predicate = main()::<lambda(T)>; T = int]' called in a constant expression
27 | return foo(
| ~~~^
28 | []<typename T>(T)
| ~~~~~~~~~~~~~~~~~
29 | {
| ~
30 | return std::is_integral_v<std::decay_t<T>>;
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
31 | },
| ~~
32 | 0);
| ~~
<source>:9:16: note: 'consteval auto foo(Predicate, T) [with Predicate = main()::<lambda(T)>; T = int]' is not usable as a 'constexpr' function because:
9 | consteval auto foo(Predicate p, T x) noexcept {
|
【问题讨论】:
-
fwiw,区别似乎是
0vsbasic_type<int>{}而不是std::decay_t<T>vsT(godbolt.org/z/5Mfe14MxW) -
鉴于所有编译器(gcc、clang、msvc)都有相同的结果和有点奇怪的规则 w.r.t.
if constexpr我倾向于相信这个错误是正确的(但不是 100% 肯定)。你可以尝试用实际的模板参数重写你的 foo 替换auto参数吗?可能会更清楚。 -
我添加了没有自动参数@DanM的函数。
-
consteval和constexpr函数可以有非编译时参数。这意味着编译器在编译此函数时会做出最一般的假设。这个假设是参数是非编译时的。这意味着编译器不能保证您的if-constexpr始终是编译时,因此会出现错误。如果您将所有参数作为模板auto函数的参数,那么它应该编译良好。 -
但它实际上并不依赖于你传入的值,只依赖于值的类型,这在编译时总是已知的?