不能使用嵌套类的constexpr函数

问题描述 投票:0回答:2
struct Foo
{
    struct Bar
    {
        int data = 0;

        //constexpr Bar() = default; // Doesn't work either
        constexpr Bar() : data(0) {}
    };

    static constexpr Bar bar = {}; // ERROR
    //static constexpr Bar bar = {0}; // Works if the ctor from Bar is removed
};

Clang 和 GCC(使用 std=c++20)说我尝试使用的构造函数未定义。但如果我将

constexpr
更改为
inline
,它就会起作用。我想了解使用“contexpr”有什么问题。

c++ c++20 constexpr
2个回答
0
投票

编译器分两遍解析一个类。第一遍处理成员变量和函数声明,第二遍处理函数主体,这允许您在该函数中使用在函数下面定义的成员变量。

当类嵌套时,第一遍遍历整个外部类(包括所有嵌套类),然后类似地第二遍遍历整个外部类(包括嵌套类)。

显然,

constexpr
静态变量初始化发生在第一遍期间,而非
constexpr
inline
)静态变量初始化发生在第二遍期间。

(上一段纯粹是根据编译器的行为方式进行的猜测。不确定这里的标准是什么,但这就是 GCC 和 Clang 的运行方式。)

当你摆脱构造函数并执行

= {0}
时,即聚合初始化,它根本不使用构造函数,因此可以在第一遍中使用。


-3
投票

您看到的错误与

static constexpr Bar bar
内的
struct Foo
成员变量的初始化有关。当您定义
constexpr
变量时,初始化器必须是
constant expression
,这是比简单的
compile-time constant
更严格的要求。

在您的情况下,

Bar
的默认构造函数使用成员初始化语法将
data
初始化为
0
。虽然这看起来像一个常量表达式,但实际上它不符合 C++ 标准对常量表达式的要求。

要初始化

constexpr
变量,用于初始化它的表达式必须是常量表达式。让代码与
constexpr
配合使用的一种方法是将
Bar
的默认构造函数更改为
constexpr constructor
,如下所示:

struct Bar
{
    int data = 0;
   
    constexpr Bar() = default;
};

通过此更改,您应该能够将

bar
定义为
constexpr
变量:

static constexpr Bar bar = {};

请注意,只有当您使用支持非聚合类的

constexpr
构造函数(C++17 中引入)的编译器时,此更改才有效。如果您使用的是旧版本的 C++ 标准,则需要坚持使用
inline
关键字而不是
constexpr

© www.soinside.com 2019 - 2024. All rights reserved.