Is a constexpr array necessarily odr-used when subscripted?

前端 未结 3 1258
情深已故
情深已故 2020-11-28 11:03

Given the following code:

struct A { static constexpr int a[3] = {1,2,3}; };

int main () {
  int a = A::a[0];
  int b  [A::a[1]];
}

is

3条回答
  •  误落风尘
    2020-11-28 11:16

    No, it is not odr-used.

    First, both your array and its elements are of literal type:

    [C++11: 3.9/10]: A type is a literal type if it is:

    • a scalar type; or
    • a class type (Clause 9) with
    • a trivial copy constructor,
    • no non-trivial move constructor,
    • a trivial destructor,
    • a trivial default constructor or at least one constexpr constructor other than the copy or move constructor, and
    • all non-static data members and base classes of literal types; or
    • an array of literal type.

    Now we look up the odr-used rules:

    [C++11: 3.2/2]: [..] A variable or non-overloaded function 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. [..]

    And here we've been referred to the rules on constant expressions, which contain nothing prohibiting your initialiser from being a constant expression; the pertinent passages are:

    [C++11: 5.19/2]: A conditional-expression is a 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 integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression, or
      • 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
      • a glvalue of literal type that refers to a non-volatile temporary object initialized with a constant expression;
    • [..]

    (Don't be put off by the name of the production, "conditional-expression": it is the only production of constant-expression and is thus the one we're looking for.)

    Then, thinking about the equivalence of A::a[0] to *(A::a + 0), after the array-to-pointer conversion you have an rvalue:

    [C++11: 4.2/1]: An lvalue or rvalue of type "array of N T" or "array of unknown bound of T" can be converted to a prvalue of type "pointer to T". The result is a pointer to the first element of the array.

    Your pointer arithmetic is then performed on this rvalue and the result is also an rvalue, used to initialise a. No lvalue-to-rvalue conversion here whatsoever, so still nothing violating "the requirements for appearing in a constant expression".

提交回复
热议问题