Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Conditional inclusion in C++11 with user-defined literal?

Tags:

c++

c++11

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"?

like image 955
Andrew Tomazos Avatar asked Feb 16 '13 21:02

Andrew Tomazos


1 Answers

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?

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-literal is treated as a call to a literal operator or literal 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-expression is a core constant expression unless 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.

like image 121
JoergB Avatar answered Sep 22 '22 01:09

JoergB