Neither argc * 0
nor argc - argc
are constant expressions, the lvalue-to-rvalue conversion is allowed in certain cases none of them apply here. If we look at the draft C++11 standard section 5.19
[expr.const] it lays out the exceptions. It says:
A conditional-expression is a core constant expression unless it involves one of the following as a potentially
evaluated subexpression [...]
and has several bullets including the following on lvalue-to-rvalue conversion:
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;
It is interesting to note that gcc does not accept the following code (see it live):
constexpr int a = argc * 2;
So it looks like gcc is saying I know the result will be zero and therefore it performs constant folding and it does not need to perform the lvalue-to-rvalue conversion of argc
to determine the result.
Unfortunately I don't see any provisions in section 5.19
that allows this kind of short-circuiting. This looks very similar to case in int a=1, is a || 1 a constant expression? which has a bug report but no one from the gcc team has replied to that one. I added a comment to that bug report indicating this seems related.
Mark's comment below indicates this is a bug:
There is a whole c++-delayed-folding branch on which some gcc developers are working, which will delay a number of optimizations and might fix this. It is important for other reasons, rejecting the code in this question is very low priority
Do constant expressions strictly require every sub-expression to be a constant expression? No, for example from 5.19
it says: (emphasis mine)
A conditional-expression is a core constant expression unless it involves one of the following as a potentially
evaluated subexpression (3.2), but subexpressions of logical AND (5.14), logical OR (5.15), and conditional
(5.16) operations that are not evaluated are not considered [...]
So the following is a constant expression:
constexpr int a = false && argc * 0;
Because argc * 0
is not evaluated since &&
evaluates left-to-right and short-circuits.