Conditional inclusion

From cppreference.com
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function declaration
inline specifier
Exception specifications (deprecated)
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
decltype (C++11)
auto (C++11)
alignas (C++11)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Implicit conversions - Explicit conversions
static_cast - dynamic_cast
const_cast - reinterpret_cast
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

The preprocessor supports conditional compilation of parts of source file. This behavior is controlled by #if, #else, #elif, #ifdef, #ifndef and #endif directives.

Syntax

#if expression
#ifdef identifier
#ifndef identifier
#elif expression
#else
#endif

Explanation

The conditional preprocessing block starts with #if, #ifdef or #ifndef directive, then optionally includes any number of #elif directives, then optionally includes at most one #else directive and is terminated with #endif directive. Any inner conditional preprocessing blocks are processed separately.

Each of #if, #elif, #else, #ifdef and #ifndef directives control code block until first #elif, #else, #endif directive not belonging to any inner conditional preprocessing blocks.

#if, #ifdef and #ifndef directives test the specified condition (see below) and if it evaluates to true, compiles the controlled code block. In that case subsequent #else and #elif directives are ignored. Otherwise, if the specified condition evaluates false, the controlled code block is skipped and the subsequent #else or #elif directive (if any) is processed. In the former case, the code block controlled by the #else directive is unconditionally compiled. In the latter case, the #elif directive acts as if it was #if directive: checks for condition, compiles or skips the controlled code block based on the result, and in the latter case processes subsequent #elif and #else directives. The conditional preprocessing block is terminated by #endif directive.

Condition evaluation

#if, #elif

The expression is a constant expression.

The expression may contain unary operators in form definedidentifier or defined (identifier). The result is 1 if the identifier was defined as a macro name or the identifier is __has_include (since C++17), otherwise the result is 0.

After all macro expansion and evaluation of defined and __has_include (since C++17) expressions, any identifier which is not a boolean literal is replaced with the number 0 (this includes identifiers that are lexically keywords, but not alternative tokens like and).

If the expression evaluates to nonzero value, the controlled code block is included and skipped otherwise.

Note: #if cond1 ... #elif cond2 is different from #if cond1 ... #else followed by #if cond3 because if cond1 is true, the second #if is skipped and cond3 does not need to be well-formed, while #elif's cond2 must be a valid expression.

(until C++14)

#ifdef, #ifndef

Checks if the identifier was defined as a macro name.

#ifdefidentifier is essentially equivalent to #if definedidentifier.

#ifndefidentifier is essentially equivalent to #if!definedidentifier.

Example

#define ABCD 2
#include <iostream>

int main()
{

#ifdef ABCD
    std::cout << "1: yes\n";
#else
    std::cout << "1: no\n";
#endif

#ifndef ABCD
    std::cout << "2: no1\n";
#elif ABCD == 2
    std::cout << "2: yes\n";
#else
    std::cout << "2: no2\n";
#endif

#if!defined(DCBA) && (ABCD < 2*4-3)
    std::cout << "3: yes\n";
#endif
}

Output:

1: yes
2: yes
3: yes

Defect reports

The following behavior-changing defect reports were applied retroactively to previously published C++ standards.

DR Applied to Behavior as published Correct behavior
CWG 1955 C++14 failed #elif's expression was required to be valid failed elif is skipped

See also