访问静态 constexpr float 成员时未定义的引用
undefined reference when accessing static constexpr float member
此代码有效:
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: In function 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 读取
A variable whose name appears as a potentially-evaluated expression is
odr-used unless it is an object that satisfies the requirements for
appearing in a constant expression (5.19) and the lvalue-to-rvalue
conversion (4.1) is immediately applied.
很明显,l-t-r 转换会立即应用,浮点类型的 constexpr
变量可以出现在常量表达式中,如 [expr.const]/(2.7.1):
A conditional-expression is a core constant expression unless it
involves one of the following as a potentially evaluated subexpression
[..]
- an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a glvalue of literal type that refers to a non-volatile object defined with
constexpr
, or that refers to a sub-object of such an
object, or
似乎是一个 Clang 错误。
有趣的是,如果我们改用 Blob::a
,clang
不会抱怨:
auto c = Blob::a;
这对于确定它是否被 odr 使用无关紧要。所以这看起来像一个 clang
错误,我可以在 clang 3.7 using no optimization only. We can tell this is an odr issue since adding a out of class definition fixes the issue (see it live 上重现):
constexpr float Blob::a ;
那么什么时候需要定义一个static constexpr class成员呢?这在 9.4.2
[class.static.data] 部分中有所介绍,它说(强调我的前进):
A static data member of literal type can be declared in the
class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer
in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both
these cases, the member may appear in constant expressions. —end note ] The member shall still be defined
in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not
contain an initializer.
如果是odr-used,需要定义。它是 odr 使用的吗?不它不是。 3.2
[basic.def.odr] 部分中的原始 C++11 措辞说:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression
thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an
object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue
conversion (4.1) is immediately applied.
a
满足这两个条件,它是一个常量表达式并且立即应用左值到右值的转换。 Defect Report 712 更改了适用于 C++11 的措辞,因为它是一个缺陷报告,3.2
现在说:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the
lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial
functions and, if x is an object, ex is an element of the set of potential results of an expression e, where
either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression
匹配的潜在结果是:
If e is an id-expression (5.1.1), the set contains only e.
它是一个常量表达式,并且应用了左值到右值的转换,因此它不被 odr 使用。
此代码有效:
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: In function
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 读取
A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.
很明显,l-t-r 转换会立即应用,浮点类型的 constexpr
变量可以出现在常量表达式中,如 [expr.const]/(2.7.1):
A conditional-expression is a core constant expression unless it involves one of the following as a potentially evaluated subexpression [..]
- an lvalue-to-rvalue conversion (4.1) unless it is applied to
- a glvalue of literal type that refers to a non-volatile object defined with
constexpr
, or that refers to a sub-object of such an object, or
似乎是一个 Clang 错误。
有趣的是,如果我们改用 Blob::a
,clang
不会抱怨:
auto c = Blob::a;
这对于确定它是否被 odr 使用无关紧要。所以这看起来像一个 clang
错误,我可以在 clang 3.7 using no optimization only. We can tell this is an odr issue since adding a out of class definition fixes the issue (see it live 上重现):
constexpr float Blob::a ;
那么什么时候需要定义一个static constexpr class成员呢?这在 9.4.2
[class.static.data] 部分中有所介绍,它说(强调我的前进):
A static data member of literal type can be declared in the class definition with the constexpr specifier; if so, its declaration shall specify a brace-or-equal-initializer in which every initializer-clause that is an assignment-expression is a constant expression. [ Note: In both these cases, the member may appear in constant expressions. —end note ] The member shall still be defined in a namespace scope if it is odr-used (3.2) in the program and the namespace scope definition shall not contain an initializer.
如果是odr-used,需要定义。它是 odr 使用的吗?不它不是。 3.2
[basic.def.odr] 部分中的原始 C++11 措辞说:
An expression is potentially evaluated unless it is an unevaluated operand (Clause 5) or a subexpression thereof. A variable whose name appears as a potentially-evaluated expression is odr-used unless it is an object that satisfies the requirements for appearing in a constant expression (5.19) and the lvalue-to-rvalue conversion (4.1) is immediately applied.
a
满足这两个条件,它是一个常量表达式并且立即应用左值到右值的转换。 Defect Report 712 更改了适用于 C++11 的措辞,因为它是一个缺陷报告,3.2
现在说:
A variable x whose name appears as a potentially-evaluated expression ex is odr-used unless applying the lvalue-to-rvalue conversion (4.1) to x yields a constant expression (5.19) that does not invoke any non-trivial functions and, if x is an object, ex is an element of the set of potential results of an expression e, where either the lvalue-to-rvalue conversion (4.1) is applied to e, or e is a discarded-value expression
匹配的潜在结果是:
If e is an id-expression (5.1.1), the set contains only e.
它是一个常量表达式,并且应用了左值到右值的转换,因此它不被 odr 使用。