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.
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:
(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 typeT
, 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.
Arrays size must be compile-time constants, but in the second example the initialization of A::i
doesn't happen until run-time.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With