Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are these snippets handled differently by GCC?

The first snippet compiles without any warnings (live example):

#include <iostream>

struct A {
  constexpr A(): i(5){}
  constexpr operator int() { return 5; }
  int i;
};

int main() {
    A a;
    int b[a]{ 0, 1, 2, 3, 4 };
    std::cout << b[4] << '\n';
}

Now alter the above snippet by returning i in the conversion operator (live example):

constexpr operator int() { return i; }

GCC warns that b is a VLA.

To me, both variants seem to conform to paragraph §5.19 [expr.const]/3 in C++14.

like image 463
Ayrosa Avatar asked Dec 21 '15 13:12

Ayrosa


2 Answers

You're performing an l-t-r conversion on i, but for [expr.const]/(2.7) not to be violated here, (2.7.3) must be applicable:

enter image description here

(2.7.1) concerns complete objects, (2.7.2) talks about string literals and (2.7.4) is about objects whose lifetime began within the evaluation of the expression - inapplicable since a's declaration precedes b's.

Define a as constexpr and the code is compliant.


A little addendum to clarify what the standard says: The expression inside the brackets must be a converted constant expression of type std::size_t ([dcl.array]/1), which is defined in [expr.const]/4 as

A converted constant expression of type T is an expression, implicitly converted to type T, where the converted expression is a constant expression and […requirements that are met…]

Thus, really, the standard is interested in whether or not

constexpr std::size_t s = a; 

would be valid. Which it isn't, for the aforementioned reasons - trying to use a subobject of a previously defined, non-constexpr object.

like image 77
Columbo Avatar answered Nov 10 '22 15:11

Columbo


Arrays size must be compile-time constants, but in the second example the initialization of A::i doesn't happen until run-time.

like image 4
Some programmer dude Avatar answered Nov 10 '22 15:11

Some programmer dude