Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

int a=1, is a || 1 a constant expression?

N4527 5.20[expr.const]p5

A constant expression is either a glvalue core constant expression whose value refers to an entity that is a permitted result of a constant expression (as defined below), or a prvalue core constant expression whose value is an object where, for that object and its subobjects:

— each non-static data member of reference type refers to an entity that is a permitted result of a constant expression, and

— if the object or subobject is of pointer type, it contains the address of an object with static storage duration, the address past the end of such an object (5.7), the address of a function, or a null pointer value.

An entity is a permitted result of a constant expression if it is an object with static storage duration that is either not a temporary object or is a temporary object whose value satisfies the above constraints, or it is a function.

void foo(){
    int a = 1;
    int b[a || 1]{};//ok in gcc 5.1.0, error in clang 3.8.0
    static_assert(a || 1,"");//ok in gcc 5.1.0, error in clang 3.8.0
    switch(1){
        case a || 1://ok in gcc 5.1.0, error in clang 3.8.0
            ;
        }
}

Is a || 1 a constant expression?


N4527 5.20[expr.const]p2

A conditional-expression e is a core constant expression unless the evaluation of e, following the rules of the abstract machine (1.9), would evaluate one of the following expressions:

(2.7) — an lvalue-to-rvalue conversion (4.1) unless it is applied to

(2.7.1) — a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or

(2.7.2) — a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or

(2.7.3) — a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or

(2.7.4) — a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

Is a || 1 a core constant expression?

like image 772
stackcpp Avatar asked Jul 20 '15 21:07

stackcpp


People also ask

What is the constant expression?

A constant expression is an expression that contains only constants. A constant expression can be evaluated during compilation rather than at run time, and can be used in any place that a constant can occur.

What is the constant expression in C++?

A constant value is one that doesn't change. C++ provides two keywords to enable you to express the intent that an object is not intended to be modified, and to enforce that intent. C++ requires constant expressions — expressions that evaluate to a constant — for declarations of: Array bounds.

Is constexpr a const?

A constexpr variable must be initialized at compile time. All constexpr variables are const . A variable can be declared with constexpr , when it has a literal type and is initialized. If the initialization is performed by a constructor, the constructor must be declared as constexpr .

What is a constant expression in Java?

A constant expression is an expression that yields a primitive type or a String, and whose value can be evaluated at compile time to a literal. The expression must evaluate without throwing an exception, and it must be composed of only the following: Primitive and String literals.


Video Answer


3 Answers

a is not constant expression(see standard quote below) and therefore:

a || 1 

Is not a constant expression either, although we know the expression has to evaluate to true the standard requires left to right evaluation here and I see no exceptions that would allow the compiler to skip the lvalue-to-rvalue conversion of a.

but:

const int a = 1;

Could be used in a constant expression because it fall under the exception from 5.20p2 (emphasis mine):

an lvalue-to-rvalue conversion (4.1) unless it is applied to

  • a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or
  • a non-volatile glvalue that refers to a subobject of a string literal (2.13.5), or
  • a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or
  • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e

This rule is also why the original case is not a constant expression since none of the exception apply.

Perhaps gcc is allowing this:

int b[a || 1]{};

as a variable length array as an extension, although it should provide a warning using -pedantic. Although that would not explain the static_assert case, they could be constant folding it but I don't think the as-if rule would allow it to be considered a constant expression.

Update, possible gcc extension

From this bug report RHS of logical operators may render LHS unevaluated in constant-expression this looks like a possible gcc extension:

This compiles without incident, despite using a non-constant object in a constant-expression:

int i;
static_assert( i || true, "" );
static_assert( ! ( i && false ), "" );

It appears to be assuming that || and && are commutative, but short-circuiting only works in one direction.

and the final comment says:

I think this is a purposeful language extension, which could use a switch to disable. It would be nice if static_assert were always strict.

This seems like a non-conforming extension that should trigger a warning when using the -pedantic flag similar in vain to issue in Is it a conforming compiler extension to treat non-constexpr standard library functions as constexpr?.

C++11/C++14 Quote

Section 5.20 is section 5.19 in C++14 and C++11, the relevant quote from the draft C++14 standard is:

an lvalue-to-rvalue conversion (4.1) unless it is applied to

  • a non-volatile glvalue of integral or enumeration type that refers to a non-volatile const object with a preceding initialization, initialized with a constant expression [ Note: a string literal (2.14.5) corresponds to an array of such objects. —end note ], or

  • a non-volatile glvalue that refers to a non-volatile object defined with constexpr, or that refers to a non-mutable sub-object of such an object, or

  • a non-volatile glvalue of literal type that refers to a non-volatile object whose lifetime began within the evaluation of e;

and for the draft C++11 standard is:

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 whose lifetime has not ended, initialized with a constant expression;

like image 174
Shafik Yaghmour Avatar answered Oct 18 '22 05:10

Shafik Yaghmour


Repeating your quote:

(2.7) — an lvalue-to-rvalue conversion (4.1) unless it is applied to

(2.7.1) — a non-volatile glvalue of integral or enumeration type that refers to a complete non-volatile const object with a preceding initialization, initialized with a constant expression, or

a involves an lvalue-to-rvalue conversion. Since a is not a const object, that means a is not a core constant expression; therefore a || 1 is not one either.

However if your code were:

const int a = 1;

then a || 1 would be a core constant expression.

like image 22
M.M Avatar answered Oct 18 '22 06:10

M.M


If the compiler checks the entire assignment chain, then it can determine that "a || 1" is a constant expression. However, since a is a variable, unless the compiler checks that a has not been assigned, it has no way of knowing that "a || 1" is a constant expression.

like image 1
Jon Trauntvein Avatar answered Oct 18 '22 06:10

Jon Trauntvein