我们如何理解关于 constexpr 的“如果可能”

Posted

技术标签:

【中文标题】我们如何理解关于 constexpr 的“如果可能”【英文标题】:How do we understand "if possible" about constexpr 【发布时间】:2021-09-24 03:00:24 【问题描述】:

我已经阅读了关于constexpr的链接:https://en.cppreference.com/w/cpp/language/constexpr

它表示 constexpr 说明符声明可以在编译时评估函数或变量的值。

据我了解,这意味着constexpr 指定的变量可能会或可能不会在编译时进行评估。

This link 告诉我同样的事情:constexpr 变量不是编译时值。

但是,我做了一个测试,让我很困惑:https://godbolt.org/z/9ajb4xKK8

如您所见,变量a 必须在编译时求值,否则不能用于声明数组。而变量s不能被constexpr指定,因为std::string的构造函数不能在编译时调用。

总之,这个测试似乎告诉我constexpr 必须在编译时评估该值。不然怎么用a这个变量来声明数组呢?

我理解错了什么?

编辑

我知道constexpr 函数可以在运行时或编译时调用。例如,如果我们将运行时参数传递给constexpr 函数,该函数将在运行时被调用,我理解。

但似乎必须在编译时评估 constexpr 变量。我可以说任何constexpr 变量都必须在编译时进行评估吗?

【问题讨论】:

您发现了一个示例,其中constexpr 必须在编译时出现。还有其他示例可以在运行时使用。 @463035818_is_not_a_number 我知道constexpr 函数可以在运行时或编译时调用。但我不明白如何在运行时而不是在编译时评估 constexpr 变量。如您所见,如果constexpr 变量无法在编译时求值,例如std::string s,则会产生错误。那么为什么我们不能说必须在编译时评估 constexpr 变量呢? 我认为constinit 更符合您的预期。据我了解,constexpr 更明确和更具表现力。考虑您想在需要编译时间常数的上下文中使用x,您可以编写const int x = foo();,这在任何情况下都可以,但稍后在需要编译时间常数的上下文中使用x 可能会失败,具体取决于foo。另一方面,当foo 不是 constexpr 时,constexpr int x = foo(); 会提前失败 cppreference 是为了“简化”标准而编写的,正式定义见dcl.constexpr。 constexpr 变量仅是编译时,而 constexpr 函数是编译或运行时取决于上下文。 【参考方案1】:

首先,godbolt 链接中使用的编译器 (gcc 11.1) 允许可变长度数组。所以a not 必须是一个常量表达式。即下面的这个sn-p代码将被接受

int a = 5;
int arr[a];

但是当你确实需要某个常量表达式时,constexpr 将允许你使用其中的变量/函数。

constexpr - 指定变量或函数的值可以出现在>常量表达式

例如,当您使用std::array 模板创建数组时,大小必须是常量

所以这样做是不行的

int a = 5;
std::array<int, a> arr;

另一方面,constexpr 允许在常量表达式中使用a,因此您可以这样做

constexpr int a = 5;
std::array<int, a> arr;

【讨论】:

以上是关于我们如何理解关于 constexpr 的“如果可能”的主要内容,如果未能解决你的问题,请参考以下文章

c++11中的constexpr概念

关于constexpr

Gcc 7.2 c++17 constexpr

Constexpr变量不是编译时间值吗?

我们应该尽可能使用 constexpr 吗?

我们应该在函数中用 constexpr 定义变量吗