Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

undefined reference when accessing static constexpr float member

This code works:

struct Blob {
    static constexpr int a = 10;
};

int main() {
    Blob b;
    auto c = b.a;
}

But if I change int to float I get an error:

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

/tmp/main-272d80.o: In function main': main.cpp:(.text+0xe): undefined reference toBlob::a'

Why can't I use a constexpr float in that way?

Compiler: Ubuntu clang version 3.5.0-4ubuntu2 (tags/RELEASE_350/final)

Tested on gcc version 4.9.1 (Ubuntu 4.9.1-16ubuntu6) and there were no error.

EDIT:

It will compile if I use -O1, -O2, -O3 or -Os but fails with -O0

like image 502
Anonymous Entity Avatar asked Feb 01 '15 15:02

Anonymous Entity


2 Answers

C++11 reads

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.

Clearly the l-t-r conversion is immediately applied, and a constexpr variable of floating point type can appear in constant expressions as per [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

Seems to be a Clang bug.

like image 185
Columbo Avatar answered Sep 18 '22 06:09

Columbo


Interestingly, if we use Blob::a instead, clang does not complain:

auto c = Blob::a;

This should not matter for determining if the it is odr-used or not. So this looks like a clang bug which I can reproduce on 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 ;

So when do you need to define a static constexpr class member? This is covered in section 9.4.2 [class.static.data] which says (emphasis mine going forward):

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.

It requires a definition if it is odr-used. Is it odr-used? No, it is not. The original C++11 wording in section 3.2 [basic.def.odr] says:

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 satisfies both conditions, it is a constant expression and the lvalue-to-rvalue conversion is immediately applied. Defect Report 712 has changed the wording which applies to C++11 since it is a defect report and 3.2 now says:

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

The potential result that matches would be:

If e is an id-expression (5.1.1), the set contains only e.

it is a constant expression and the lvalue-to-rvalue conversion is applied so it is not odr-used.

like image 25
Shafik Yaghmour Avatar answered Sep 22 '22 06:09

Shafik Yaghmour