访问静态 constexpr 浮点型成员时的未定义引用



这段代码有效:

struct Blob {
    static constexpr int a = 10;
};
int main() {
    Blob b;
    auto c = b.a;
}

但是,如果我将int更改为float,则会出现错误:

struct Blob {
    static constexpr float a = 10.0f;
};
/

tmp/main-272d80.o:在函数main': main.cpp:(.text+0xe): undefined reference to Blob::a'

为什么我不能以这种方式使用constexpr float

编译器:Ubuntu clang 版本 3.5.0-4ubuntu2 (tags/RELEASE_350/final)

在 gcc 版本 4.9.1

(Ubuntu 4.9.1-16ubuntu6)上测试,没有错误。

编辑:

如果我使用 -O1、-O2、-O3 或 -Os 但因 -O0 而失败,它将编译

C++11 读取

名称显示为潜在计算表达式的变量是 ODR 使用除非它是满足以下要求的对象 出现在常量表达式 (5.19) 和左值到右值中 转换 (4.1) 立即应用。

显然,l-t-r 转换会立即应用,浮点类型的constexpr变量可以按照 [expr.const]/(2.7.1) 出现在常量表达式中:

条件表达式是核心常量表达式,除非它 涉及以下之一作为潜在评估的子表达式 [..]

  • 左值到重值的转换 (4.1),除非它应用于
    • 文字类型的 glvalue 引用用 constexpr 定义的非易失性对象,或引用此类对象的子对象 对象,或

似乎是叮当虫。

有趣的是

,如果我们改用Blob::aclang不会抱怨:

auto c = Blob::a;

这对于确定它是否使用 odr 无关紧要。所以这看起来像一个clang错误,我可以在 clang 3.7 上重现它,而无需优化。我们可以说这是一个 odr 问题,因为添加类外定义可以解决问题(实时查看):

constexpr float Blob::a ;

那么什么时候需要定义静态 constexpr 类成员呢?这在第 9.4.2[class.static.data] 中有所介绍,其中说(强调我的):

文本类型的静态数据成员可以在 使用 constexpr 说明符进行类定义;如果是这样,其声明应指定大括号或等于初始值设定项 其中作为赋值表达式的每个初始值设定项子句都是一个常量表达式。[ 注意:在两者中 在这些情况下,成员可能出现在常量表达式中。—尾注 ] 成员仍应定义 在命名空间作用域中,如果它在程序中是 ODR 使用的 (3.2) 并且命名空间作用域定义不应 包含初始值设定项。

如果它是 odr 使用的,它需要一个定义。它是ODR使用的吗?不,不是。第3.2节[basic.def.odr]中最初的C++11措辞说:

表达式

可能会被计算,除非它是未计算的操作数(条款 5)或子表达式 其中。名称显示为潜在计算表达式的变量是 odr 使用的,除非它是 满足出现在常量表达式 (5.19) 和左值到右值中的要求的对象 转换 (4.1) 立即应用

a同时满足这两个条件,则它是一个常量表达式,并立即应用左值到右值的转换。缺陷报告 712 更改了适用于 C++11 的措辞,因为它是一份缺陷报告,3.2现在说:

名称显示为潜在计算表达式 ex 的变量 x 是 odr 使用的,除非应用 左值到重值的转换 (4.1) 到 x 产生一个常量表达式 (5.19),该表达式不会调用任何非平凡 函数,如果 x 是一个对象,则 ex 是表达式 e 的潜在结果集合中的一个元素,其中 左值到重值转换 (4.1) 应用于 E,或者 E 是丢弃值表达式

匹配的潜在结果将是:

如果 e 是 id 表达式 (5.1.1),则集合仅包含 e。

它是一个常量表达式,并且应用了左值到右值的转换,因此不使用它。

相关内容

  • 没有找到相关文章

最新更新