微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 由于定义顺序,“令人惊讶”的常量初始化

当阅读 slides about constexpr时,介绍是关于“惊奇的动态初始化与const”.例子是
struct S {
    static const int c;
};
const int d = 10 * S::c;
const int S::c = 5;

唉,音轨丢失了,笔记也是这样,所以我只能猜测这里是什么意思.

它是否正确,d“动态”初始化,因为S :: c在d之前定义? S :: c的声明在d之前可能还不够,编译器需要完整的定义,对吗?

也就是说,我怀疑在下面的例子中,d会被静态初始化吗?

struct S {
    static const int c;
};
const int S::c = 5;
const int d = 10 * S::c;  // Now _after_ defn of S::c

而且,在C11中,要完全静态初始化是什么必须是constexpr? S :: c,d或两者?

解决方法

在第一个例子中,d不是由常量表达式初始化,因为S :: c不是

a non-volatile const object with a preceding initialization,
initialized with a constant expression

(参见C 11 [expr.const] p2,lvalue-to-rvalue转换的子弹),因为S :: c的初始化不在d的初始化之前.因此,静态初始化将用于S :: c(因为它是由常量表达式初始化的),但动态初始化可以用于d.

由于静态初始化先于动态初始化,d将通过动态初始化器初始化为50.允许编译器将d的动态初始化转换为静态初始化,但如果是,则必须产生如果每个可能使用动态初始化的变量实际上都使用动态初始化,那么d将会产生这个值.在这种情况下,d被初始化为50.有关详细信息,请参阅C 11 [basic.start.init] p2.

没有办法在第一个例子中添加constexpr来保证对d进行静态初始化;为了做到这一点,您必须重新排序初始化.但是,添加constexpr将会产生第一个示例的诊断,这将至少允许您确保不使用动态初始化(您将获得静态初始化或编译错误).

您可以更新第二种情况,以确保使用静态初始化如下:

struct S {
    static const int c; // do not use constexpr here
};
constexpr int S::c = 5;
constexpr int d = 10 * S::c;

在不是定义的变量声明上使用constexpr是不正确的,或者在不包含初始化器的变量声明上使用它,因此在struct S的定义中必须使用const,而不是constexpr.这个规则是一个例外,当定义一个文字非整数类型的静态constexpr数据成员时,该类在类中指定了初始化器:

struct T { int n; };
struct U {
    static constexpr T t = { 4 };
};
constexpr T U::t;

在这种情况下,必须在类的定义中使用constexpr,以便允许提供初始化器,并且必须在静态数据成员的定义中使用constexpr,以便允许其在常量表达式中使用.

原文地址:https://www.jb51.cc/c/112537.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐