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

Categories

0 votes
335 views
in Technique[技术] by (71.8m points)

c++ - Static constexpr odr-used or not?

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

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

1 Answer

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...