In C++11 when a preprocessing directive of the form...
#if expr
...is encountered,expr is evaluated as a constant-expression as described in 16.1 [cpp.cond].
This is done after macro replacement on expr, its identifiers (and keywords) are replaced by 0, its preprocessing-tokens are converted to tokens, defined operator is evaluated, and so on.
My question is what happens when one of the tokens in expr is a user-defined-literal?
User defined literals are like function calls, but function calls can't occur in expr (I think), as a side effect of the identifier replacement. However technically user-defined-literals could survive.
I suspect it is an error, but I can't quite see how to conclude that from the standard?
Perhaps the (pedantic) impact of adding user defined literals on clause 16 [cpp] was simply ignored?
Or am I missing something?
Update:
To clarify by an example:
What does this preprocess to:
#if 123_foo + 5.5 > 100
bar
#else
baz
#endif
bar or baz or is it an error?
GCC 4.7 reports:
test.cpp:1:5: error: user-defined literal in preprocessor expression
so it thinks it is an error. Can this be justified with reference to the standard? Or is this just "implicit"?
In C++11 when a preprocessing directive of the form...
#if expr ...is encountered,expris evaluated as aconstant-expressionas described in16.1 [cpp.cond].This is done after macro replacement on
expr, its identifiers (and keywords) are replaced by0, itspreprocessing-tokensare converted totokens,definedoperator is evaluated, and so on.My question is what happens when one of the
tokensinexpris auser-defined-literal?
The program is ill-formed.
The core of my argument is gleaned from the observation in 16.1/1 footnote 147, that in translation phase 4 there are no identifiers other than macro names yet.
Argument:
According to 2.14.8 [lex.ext]/2
A
user-defined-literalis treated as a call to aliteral operatororliteral operator template(13.5.8).
So here we have a remaining call to an (operator) function even after all the substitutions described in 16.1/4. (Other attempts, for example to use a constexpr function, would be thwarted by the substitution of all non-macro identifiersby 0.)
As this occurs in translation phase 4, there are no defined or even declared functions yet; an attempted lookup of the literal-operator-id must fail (see footnote 147 in 16.1/1 for a similar argument).
From a slightly different angle, looking at 5.19/2we find:
A
conditional-expressionis acore constant expressionunless it involves one of the following as a potentially evaluated subexpression (3.2) [...]:
- [...]
- an invocation of a function other than a constexpr constructor for a literal class or a constexpr function;
- an invocation of an undefined constexpr function or an undefined constexpr constructor [...];
From this, use of a user-defined literal in a constant expression requires a defined and constexpr literal operator, which again can't be available in translation phase 4.
gcc is right to reject this.
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