【问题标题】:constexpr function call doesn't compileconstexpr 函数调用无法编译
【发布时间】:2021-08-13 19:38:48
【问题描述】:

为什么下面的代码不能编译?

#include <stdint.h>
#include <array>

class A
{
    struct Helper
    {
        static constexpr uint64_t p2(uint8_t n)
        {
            return static_cast<uint64_t>(1) << n;
        }
    };

    using DenomArray = std::array<uint64_t, Helper::p2(5)>;
};

使用 GCC 我得到:

error: 'static constexpr uint64_t A::Helper::p2(uint8_t)' called in a constant expression before its definition is complete

我的理解是应该定义 p2 函数,因为 Helper 类已完全编译。

尝试了用于 x86 和 GCC 12 的 MSVC 编译器版本 19.29.30040。

EDIT1:

模板和非模板类的行为不同。例如下面的代码编译:

template <class T>
class A
{
private:

    struct Helper
    {
        static constexpr T p2(uint8_t n)
        {
            return static_cast<T>(1) << n;
        }
    };

    using DenomArray = std::array<T, Helper::p2(5)>;
};

using IntA = A<uint64_t>;

【问题讨论】:

  • 您应该指定您使用的 C++ 版本(即 c++11、c++14...)
  • TL;骗子的博士:内联类函数的定义不是类定义的一部分。因此,它们不能用于定义类的成员。
  • @AlexisWilke 查看更新后的帖子。
  • 我重新打开了Q,这里有一个旧目标的链接供参考:stackoverflow.com/questions/56799393/…。不确定这里是哪个编译器,因为Helper::p2(5) 实际上是A::Helper::p2(5),而A 尚未定义。

标签: c++


【解决方案1】:

您定义DenomArray 的地方是A::Helper 尚未完全定义的地方,这使得A::Helper::p2(5) 成为非常量表达式。

有趣的是,将A 制作为模板可以解决这个问题——这可能是一个语言缺陷——见这里:http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_active.html#1626

更正式的:https://eel.is/c++draft/temp.arg.nontype#2

非类型模板参数的模板参数应该是 类型的转换常量表达式 ([expr.const]) 模板参数。

然后https://eel.is/c++draft/expr.const#5:

表达式 E 是核心常量表达式,除非 E、遵循抽象机的规则([intro.execution]), 将评估以下之一:

现在到您的代码违反的部分:https://eel.is/c++draft/expr.const#5.3

(5.3) 调用未定义的 constexpr 函数;

为什么它未定义? - 因为它在被认为是非完整上下文的上下文中使用:

https://eel.is/c++draft/class#mem.general-7

类(模板)的完整类上下文是 (7.1) 函数体 ([dcl.fct.def.general]), (7.2)默认参数([dcl.fct.default]), (7.3)默认模板参数([temp.param]), (7.4) noexcept-specifier ([except.spec]),或 (7.5) 默认成员 初始化器

所以它没有说struct 的主体是一个完整的类上下文。您可以将 using 放在函数体内,它会编译:

class A
{
    struct Helper
    {
        static constexpr uint64_t p2(uint8_t n)
        {
            return static_cast<uint64_t>(1) << n;
        }
    };
   void ff() {
     using DenomArray = std::array<uint64_t, Helper::p2(5)>;
   }
};

[编辑] 另外,请参见此处:https://coliru.stacked-crooked.com/a/6536fdbe1ded1d01,clang 错误与 gcc 不同,因为它说 Helper::p2(5) 是非 constexpr :

错误:非类型模板参数不是常量表达式

这就是我上面解释的。

【讨论】:

    猜你喜欢
    • 2011-12-08
    • 2021-11-28
    • 1970-01-01
    • 2017-08-11
    • 2017-06-27
    • 2020-02-10
    • 1970-01-01
    • 1970-01-01
    • 2012-01-04
    相关资源
    最近更新 更多