Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
menu search
person
Welcome To Ask or Share your Answers For Others

Categories

How come that the following works on gcc but doesn't on clang, (see it live):

constexpr int giveMeValue() { return 42; }

struct TryMe {
  static constexpr int arr[1] = {
      giveMeValue()
  };  
};

int main() {
    int val = TryMe::arr[0];
    return val;
}

I get an unresolved external symbol with clang.

Is TryMe::arr[0] an object? If it is, is it odr-used?

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
345 views
Welcome To Ask or Share your Answers For Others

1 Answer

TryMe::arr is odr-used but you don't provide a definition (see it live):

constexpr int TryMe::arr[1];

Why is the result inconsistent between gcc and clang? This is because odr violations do not require a disagnostic, from both the C++11 and C++14 draft standard (emphasis mine):

Every program shall contain exactly one definition of every non-inline function or variable that is odr-used in that program; no diagnostic required.

We can see it is odr-used from the draft C++11 standard, section 3.2 which 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.

TryMe::arr is an object and it does satisfy the requirements for appearing in a constant expression but the lvalue-to-rvalue conversion is not immediately applied to TryMe::arr but to TryMe::arr[0].

The updated wording from the draft C++14 standard which applies to C++11 as well since it was applied via a defect report(DR 712):

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 results of the expression TryMe::arr[0] is empty by the criteria in 3.2 paragraph 2 and so it is odr-used.

Note: you need to provide a definition outside of the class as per section 9.4.2 [class.static.data] which says (emphasis mine):

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

Update

T.C. pointed out defect report 1926 which adds the following bullet to 3.2 [basic.def.odr] paragraph 2:

  • If e is a subscripting operation (5.2.1 [expr.sub]) with an array operand, the set contains that operand.

Which means subscripting an array is no longer an odr-use and so the OPs code would be well-formed in C++1z and it seems like C++14 since the defect looks like it is against C++14.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
thumb_up_alt 0 like thumb_down_alt 0 dislike
Welcome to ShenZhenJia Knowledge Sharing Community for programmer and developer-Open, Learning and Share
...