【问题标题】:local constexpr variable introduces compiler error本地 constexpr 变量引入编译器错误
【发布时间】:2021-02-08 04:30:00
【问题描述】:

除非您将标记为 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 行?

【问题讨论】:

  • 我认为你应该用 [language-lawyer] 标记它并删除 [gcc]。
  • a constexpr 函数必须是合法函数,这意味着它不能在常量表达式中调用,在这种情况下它的参数可能不是常量表达式。

标签: c++ gcc c++17 constexpr


【解决方案1】:

出现这种行为是因为

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

有时允许常量表达式包含不是常量表达式的表达式本身可能令人惊讶。

【讨论】:

  • 我认为myArray.size()constexpr。你能解释一下你所说的不是per se吗?
  • @Ant 正如您在帖子中已经观察到的那样,它不是一个常量表达式,因为myArray 是一个参考参数。
【解决方案2】:

您将看到,如果您删除 constexpr,编译器会接受失败行。 constexpr 的变量必须在编译时初始化(这也意味着它是隐式静态的)。但是标记为constexpr 的函数可能可以在编译时被调用,但它不是必须的。它也可以在运行时调用,然后,这个初始化不会在编译时而是在运行时。这是被禁止的。对于constexpr 函数,您应该始终考虑它们是否也可以工作,如果您删除constexpr

【讨论】:

    猜你喜欢
    • 2020-05-21
    • 2017-08-12
    • 1970-01-01
    • 2020-03-06
    • 1970-01-01
    • 2014-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多