gpt4 book ai didi

c++ - 函数不能用作 'constexpr' 函数

转载 作者:行者123 更新时间:2023-12-04 11:18:13 25 4
gpt4 key购买 nike

看看下面的代码

#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 {
| ^~~
谁能告诉我为什么?
这是一个godbolt链接
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 {
|

最佳答案

为了评估这一点:

  if constexpr (p(x)) {
我们需要 p(x)成为一个常量表达式。某事是否符合常量表达式的规则基于您不允许做的事情列表。
xbasic_type<int>p是一个接受 basic_type<int> 的函数就值(value)而言,我们根本就没有违反任何规则。这是一个空类型,因此复制它(正如我们在这里所做的那样)实际上并不涉及任何类型的读取。这只是有效。

但是当 xintp是一个接受 int 的函数按值,这也需要复制 x但这一次涉及读取 x的值。 .因为,当然,必须以某种方式初始化参数。这确实违反了规则: [expr.const]/8说我们不允许执行:

an lvalue-to-rvalue conversion unless it is applied to

  • a non-volatile glvalue that refers to an object that is usable in constant expressions, or
  • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of E;

当我们读取一个变量的值时会发生左值到右值的转换,这两种情况都不适用。在这里,您实际上并不关心值是什么并不重要,因为 p不使用它。为了甚至能够调用 p ,你要复制 x ,而且你不能这样做。因此错误。

但是,这里的 lambda 实际上并不需要值,只需要类型,因此您可以改为这样写:
    return foo(
[]<typename T>(T const&)
{
return std::is_integral_v<std::decay_t<T>>;
},
0);
现在我们不再复制 x进入 lambda,因为 lambda 不再按值获取 - 它按引用获取。因此,我们没有违反左值到右值的转换规则(或任何其他规则),现在这是一个有效的常量表达式。

然后,作为奖励,如果您更改 foox通过引用(同样,因为您实际上并不关心值(value),所以为什么不关心):
consteval auto foo(auto p, auto const& x) noexcept {
if constexpr (p(x)) {
return 1;
} else {
return 0;
}
}
然后这两个变体都变得格式错误。两者 basic_type<int>int版本(无论您是按值还是按引用取 int)。有关此案例的更多信息,请参阅 the constexpr array size problem我目前正试图用 P2280 解决这个问题.

关于c++ - 函数不能用作 'constexpr' 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66869387/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com