Blog 2022 09 07 C++23: Preprocessing directives

C++23: Preprocessing directives

The ISO Committee accepted two proposals for C++23 related to preprocessing directives. P2334R1 is about introducing #elifdef and #elifndef and P2437R1 is introducing #warning.

What is a preprocessing directive?

First, let’s discuss what are preprocessing or prepocessor directives. They can be included both in header and implementation files and they start with a # sign. Such lines are examined and resolved before the compilation starts and as the name suggests that is done by the preprocessor. Such directives are only one line long and end with a newline, so no semicolon is required. In case you want longer directives, you have to end the line with \ in order to signal to the preprocessor that you’d continue the definiton on the next line.

If you think about simple one-liner preprocssing directives, you can think about the #include statements. What happens for #include statements is that they are basically textually replaced by files being included.

Another (in)famous usage of preprocessor directives is macros! With the directive #define we can introduce shortcuts for literals, functions, classes, whatever. The problem is that again, it’s just a textual replacement before the compilation starts. Then if you face with a syntax error or if you have to debug, you have quite a difficult job because what was compiled was textually different from what you have in your source code. But enough on why macros are bad. Read more here.

If you are looking for an example for a multiline directive, it’s usually a macro defined with #define such as

#define square(x) \
      ((x)        \
        *         \
      (x))        \

#elifdef and #elifndef

C++23 is introducing elifdef and elifndef. Interestingly this is coming from WG14, so the ISO work group working on the C language. These new directives are going to be part of C23, and the C++ working group (WG21) decided to adopt these changes in order to avoid preprocessor incompatibilities with C.

In any case, it’s going to help save some keystrokes, and it reads relatively well.

Probably you’ve seen #ifndef at least in some header guards. #ifndef identifier serving a shortcut for #if !defined(identifier) and there is also #ifdef identifier is a shorthand for #if defined(identifier). In the C++ language we don’t only have if, but there is also else if for supporting multibranch conditionals. It’s similar in the preprocessor directives world, where we don’t only have #if, but also #elif. Until now, they had no similar shorthands, but C23 and C++23 makes life easier for those who use these multibranch conditional preprocessor directives. And in fact, not just easier but also more symmetric and readable.

There is very little reason to have shorthands for one and not the other.


As I explained in C++23: Narrowing contextual conversions to bool, a new standard doesn’t always change the compiler implementations. Sometimes, a new standard just gets closer to existing implementations.

It’s the case with the introduction of #warning to the standard. It had been already implemented by all the major compilers, and now both the C and the C++ standard is going to adopt it.

So what does #warning? It invokes diagnostic message by the preprocessor, without stopping the translation. That’s the difference between #error and #warning. The former stops the translation, while the latter does not.

Its usage could look like this:

#ifndef FOO 
#warning "FOO defined, performance might be limited"


It might be a bit suprising, but C++23 (and C23) introduces changes to the preprocessor directives. With the introduction of #elifdef and #elifndef the language becomes more round as we already had #ifdef and #ifndef and with the standardization of #warning, the standard comes closer to the compiler implementations.

How often do you use preprocessor directives apart from #include and header gurads?

Connect deeper

If you liked this article, please

This post is licensed under CC BY 4.0 by the author.