本地 constexpr 变量引入编译器错误

local constexpr variable introduces compiler error

除非您将标记为 ok 的行替换为标记为 fails 的行,否则以下代码将按预期编译和工作。唯一的区别是我正在创建一个本地临时 constexpr 变量。我不明白为什么它只在一种情况下失败。

#include <array>

using TArray = std::array<int, 2>;
using TSize  = TArray::size_type;

constexpr TSize Fn(const TArray& myArray) 
{
    //constexpr TSize ret{myArray.size()}; return ret; // fails
    return myArray.size();                           // ok
}

int main()
{
    constexpr TArray ar{};
    constexpr TSize i{Fn(ar)};
    return i;
}

我在 gcc 和 c++17 中遇到的错误是

<source>: In function 'constexpr TSize Fn(const TArray&)':
<source>:15:39: error: 'myArray' is not a constant expression
   15 |     constexpr TSize ret{myArray.size()}; return ret; // fails

我想补充一点,我意识到错误状态 myArray 不是常量表达式。我不能使它成为常量表达式,因为它是一个引用参数。
我的问题是 而不是 如何修复代码或使其正常工作。这就是为什么编译器接受 ok like 但不接受 fail 行?

如果删除 constexpr,您将看到编译器接受失败行。 constexpr 的变量必须在编译时初始化(这也意味着它是隐式静态的)。但是标记为 constexpr 潜在 的函数可以 在编译时调用,但它不是必须的。它也可以在运行时调用,这样初始化就不会在编译时发生,而是在运行时发生。那是被禁止的。对于 constexpr 函数,如果删除 constexpr.

,您应该始终考虑它们是否也可以工作

出现此行为是因为

  • 出现在函数内部的表达式myArray.size()本身并不是常量表达式,因为它访问的引用变量的初始化在这个表达式。
  • 表达式 Fn(ar) 常量表达式,尽管它的计算涉及函数调用内部的 myArray.size() 的计算。当 myArray.size() 作为 Fn(ar) 的一部分被评估 时,引用参数的初始化是可见的(函数调用本身执行该初始化)。
  • 当你声明一个变量constexpr时,编译器会判断该变量的初始化是否是一个有效的常量表达式本身;
  • 因此,Fn(ar) 可用于初始化一个 constexpr 变量,但 myArray.size() 不能。

有时允许常量表达式包含本身不是常量表达式的表达式

可能令人惊讶