[cpp.cond] # 15 Preprocessing directives [[cpp]](./#cpp) ## 15.2 Conditional inclusion [cpp.cond] [defined-macro-expression:](#nt:defined-macro-expression "15.2 Conditional inclusion [cpp.cond]") defined [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") defined ( [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") ) [h-preprocessing-token:](#nt:h-preprocessing-token "15.2 Conditional inclusion [cpp.cond]") any [*preprocessing-token*](lex.pptoken#nt:preprocessing-token "5.5 Preprocessing tokens [lex.pptoken]") other than > [h-pp-tokens:](#nt:h-pp-tokens "15.2 Conditional inclusion [cpp.cond]") [*h-preprocessing-token*](#nt:h-preprocessing-token "15.2 Conditional inclusion [cpp.cond]") [*h-pp-tokens*](#nt:h-pp-tokens "15.2 Conditional inclusion [cpp.cond]")opt [header-name-tokens:](#nt:header-name-tokens "15.2 Conditional inclusion [cpp.cond]") [*string-literal*](lex.string#nt:string-literal "5.13.5 String literals [lex.string]") < [*h-pp-tokens*](#nt:h-pp-tokens "15.2 Conditional inclusion [cpp.cond]") > [has-include-expression:](#nt:has-include-expression "15.2 Conditional inclusion [cpp.cond]") __has_include ( [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") ) __has_include ( [*header-name-tokens*](#nt:header-name-tokens "15.2 Conditional inclusion [cpp.cond]") ) [has-embed-expression:](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]") __has_embed ( [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")opt ) __has_embed ( [*header-name-tokens*](#nt:header-name-tokens "15.2 Conditional inclusion [cpp.cond]") [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1 Preamble [cpp.pre]")opt ) [has-attribute-expression:](#nt:has-attribute-expression "15.2 Conditional inclusion [cpp.cond]") __has_cpp_attribute ( [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") ) [1](#1) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L380) The expression that controls conditional inclusion shall be an integral constant expression except that identifiers (including those lexically identical to keywords) are interpreted as described below[123](#footnote-123 "Because the controlling constant expression is evaluated during translation phase 4, all identifiers either are or are not macro names — there simply are no keywords, enumeration constants, etc.") and it may contain zero or more[*defined-macro-expression*](#nt:defined-macro-expression "15.2 Conditional inclusion [cpp.cond]")*s*,[*has-include-expression*](#nt:has-include-expression "15.2 Conditional inclusion [cpp.cond]")*s*,[*has-attribute-expression*](#nt:has-attribute-expression "15.2 Conditional inclusion [cpp.cond]")*s*, and/or [*has-embed-expression*](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]")*s* as unary operator expressions[.](#1.sentence-1) A [*defined-macro-expression*](#nt:defined-macro-expression "15.2 Conditional inclusion [cpp.cond]") shall not appear within a [*has-include-expression*](#nt:has-include-expression "15.2 Conditional inclusion [cpp.cond]") or [*has-embed-expression*](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]")[.](#1.sentence-2) [2](#2) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L401) A [*defined-macro-expression*](#nt:defined-macro-expression "15.2 Conditional inclusion [cpp.cond]") evaluates to 1 if the identifier is currently defined as a macro name (that is, if it is predefined or if it has one or more active macro definitions ([[cpp.import]](cpp.import "15.6 Header unit importation")), for example because it has been the subject of a#define preprocessing directive without an intervening#undef directive with the same subject identifier), 0 if it is not[.](#2.sentence-1) [3](#3) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L415) The header or source file identified by the parenthesized preprocessing token sequence in each contained [*has-include-expression*](#nt:has-include-expression "15.2 Conditional inclusion [cpp.cond]") is searched for as if that preprocessing token sequence were the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") of a #include directive, except that no further macro expansion is performed[.](#3.sentence-1) If the preprocessing token sequence does not consist solely of a [*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") or cannot be combined ([[cpp.include]](cpp.include "15.3 Source file inclusion")) into a single[*header-name*](lex.header#nt:header-name "5.6 Header names [lex.header]") preprocessing token, the program is ill-formed[.](#3.sentence-2) The [*has-include-expression*](#nt:has-include-expression "15.2 Conditional inclusion [cpp.cond]") evaluates to 1 if the search for the source file succeeds, and to 0 if the search fails[.](#3.sentence-3) [4](#4) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L429) The parenthesized preprocessing token sequence of each contained[*has-embed-expression*](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]") is processed as if that preprocessing token sequence were the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") of a #embed directive ([[cpp.embed]](cpp.embed "15.4 Resource inclusion")), except that no further macro expansion is performed[.](#4.sentence-1) The [*has-embed-expression*](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]") evaluates to: - [(4.1)](#4.1) __STDC_EMBED_FOUND__ if the search for the resource succeeds, all the given [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]")*s* in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]") are supported, and the resource is not empty[.](#4.1.sentence-1) - [(4.2)](#4.2) Otherwise, __STDC_EMBED_EMPTY__ if the search for the resource succeeds, all the given [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]")*s* in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1 Preamble [cpp.pre]") are supported, and the resource is empty[.](#4.2.sentence-1) - [(4.3)](#4.3) Otherwise, __STDC_EMBED_NOT_FOUND__[.](#4.3.sentence-1) [*Note [1](#note-1)*: An unrecognized [*embed-parameter*](cpp.pre#nt:embed-parameter "15.1 Preamble [cpp.pre]") in an [*has-embed-expression*](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]") is not ill-formed and is instead treated as not supported[.](#4.sentence-3) — *end note*] [5](#5) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L453) Each [*has-attribute-expression*](#nt:has-attribute-expression "15.2 Conditional inclusion [cpp.cond]") is replaced by a non-zero [*pp-number*](lex.ppnumber#nt:pp-number "5.7 Preprocessing numbers [lex.ppnumber]") matching the form of an [*integer-literal*](lex.icon#nt:integer-literal "5.13.2 Integer literals [lex.icon]") if the implementation supports an attribute with the name specified by interpreting the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]"), after macro expansion, as an [*attribute-token*](dcl.attr.grammar#nt:attribute-token "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]"), and by 0 otherwise[.](#5.sentence-1) The program is ill-formed if the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1 Preamble [cpp.pre]") do not match the form of an [*attribute-token*](dcl.attr.grammar#nt:attribute-token "9.13.1 Attribute syntax and semantics [dcl.attr.grammar]")[.](#5.sentence-2) [6](#6) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L465) For an attribute specified in this document, it is implementation-defined whether the value of the [*has-attribute-expression*](#nt:has-attribute-expression "15.2 Conditional inclusion [cpp.cond]") is 0 or is given by Table [21](#tab:cpp.cond.ha "Table 21: __has_­cpp_­attribute values")[.](#6.sentence-1) For other attributes recognized by the implementation, the value isimplementation-defined[.](#6.sentence-2) [*Note [2](#note-2)*: It is expected that the availability of an attribute can be detected by any non-zero result[.](#6.sentence-3) — *end note*] Table [21](#tab:cpp.cond.ha) — __has_cpp_attribute values [[tab:cpp.cond.ha]](./tab:cpp.cond.ha) | [🔗](#tab:cpp.cond.ha-row-1)
**Attribute** | **Value** | | --- | --- | | [🔗](#tab:cpp.cond.ha-row-2)
assume | 202207L | | [🔗](#tab:cpp.cond.ha-row-3)
deprecated | 201309L | | [🔗](#tab:cpp.cond.ha-row-4)
fallthrough | 201603L | | [🔗](#tab:cpp.cond.ha-row-5)
indeterminate | 202403L | | [🔗](#tab:cpp.cond.ha-row-6)
likely | 201803L | | [🔗](#tab:cpp.cond.ha-row-7)
maybe_unused | 201603L | | [🔗](#tab:cpp.cond.ha-row-8)
no_unique_address | 201803L | | [🔗](#tab:cpp.cond.ha-row-9)
nodiscard | 201907L | | [🔗](#tab:cpp.cond.ha-row-10)
noreturn | 200809L | | [🔗](#tab:cpp.cond.ha-row-11)
unlikely | 201803L | [7](#7) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L496) The#ifdef, #ifndef, #elifdef, and #elifndef directives, and the defined conditional inclusion operator, shall treat __has_include, __has_embed, and __has_cpp_attribute as if they were the names of defined macros[.](#7.sentence-1) The identifiers __has_include, __has_embed, and __has_cpp_attribute shall not appear in any context not mentioned in this subclause[.](#7.sentence-2) [8](#8) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L506) Each preprocessing token that remains (in the list of preprocessing tokens that will become the controlling expression) after all macro replacements have occurred shall be in the lexical form of a [token](lex.token "5.10 Tokens [lex.token]")[.](#8.sentence-1) [9](#9) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L512) Preprocessing directives of the forms # if [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]") [*group*](cpp.pre#nt:group "15.1 Preamble [cpp.pre]")opt # elif [*constant-expression*](expr.const#nt:constant-expression "7.7 Constant expressions [expr.const]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]") [*group*](cpp.pre#nt:group "15.1 Preamble [cpp.pre]")opt check whether the controlling constant expression evaluates to nonzero[.](#9.sentence-1) [10](#10) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L522) Prior to evaluation, macro invocations in the list of preprocessing tokens that will become the controlling constant expression are replaced (except for those macro names modified by thedefined unary operator), just as in normal text[.](#10.sentence-1) If replacement of macros in the preprocessing tokens following the sequence__has_embed ( and before a matching ) (possibly produced by macro expansion) encounters a preprocessing token that is one of the [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]")*s*limit, prefix, suffix, or if_empty and that [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") is defined as a macro ([[cpp.replace.general]](cpp.replace.general "15.7.1 General")), the program is ill-formed[.](#10.sentence-2) If the preprocessing tokendefined is generated as a result of this replacement process or use of thedefined unary operator does not match one of the two specified forms prior to macro replacement, the program is ill-formed, no diagnostic required[.](#10.sentence-3) [11](#11) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L547) After all replacements due to macro expansion and evaluations of[*defined-macro-expression*](#nt:defined-macro-expression "15.2 Conditional inclusion [cpp.cond]")*s*,[*has-include-expression*](#nt:has-include-expression "15.2 Conditional inclusion [cpp.cond]")*s*,[*has-embed-expression*](#nt:has-embed-expression "15.2 Conditional inclusion [cpp.cond]")*s*, and[*has-attribute-expression*](#nt:has-attribute-expression "15.2 Conditional inclusion [cpp.cond]")*s* have been performed, all remaining identifiers and keywords, except fortrue andfalse, are replaced with the [*pp-number*](lex.ppnumber#nt:pp-number "5.7 Preprocessing numbers [lex.ppnumber]")0, and then each preprocessing token is converted into a token[.](#11.sentence-1) [*Note [3](#note-3)*: An [alternative token](lex.digraph "5.9 Alternative tokens [lex.digraph]") is not an identifier, even when its spelling consists entirely of letters and underscores[.](#11.sentence-2) Therefore it is not subject to this replacement[.](#11.sentence-3) — *end note*] [12](#12) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L570) The resulting tokens comprise the controlling constant expression which is evaluated according to the rules of [[expr.const]](expr.const "7.7 Constant expressions") using arithmetic that has at least the ranges specified in [[support.limits]](support.limits "17.3 Implementation properties")[.](#12.sentence-1) For the purposes of this token conversion and evaluation all signed and unsigned integer types act as if they have the same representation as, respectively,intmax_t or uintmax_t ([[cstdint.syn]](cstdint.syn "17.4.1 Header synopsis"))[.](#12.sentence-2) [*Note [4](#note-4)*: Thus on an implementation where std​::​numeric_limits​::​max() is 0x7FFF and std​::​numeric_limits​::​max() is 0xFFFF, the integer literal 0x8000 is signed and positive within a #if expression even though it is unsigned in [translation phase 7](lex.phases "5.2 Phases of translation [lex.phases]")[.](#12.sentence-3) — *end note*] This includes interpreting [*character-literal*](lex.ccon#nt:character-literal "5.13.3 Character literals [lex.ccon]")*s* according to the rules in [[lex.ccon]](lex.ccon "5.13.3 Character literals")[.](#12.sentence-4) [*Note [5](#note-5)*: The associated character encodings of literals are the same in #if and #elif directives and in any expression[.](#12.sentence-5) — *end note*] Each subexpression with typebool is subjected to integral promotion before processing continues[.](#12.sentence-6) [13](#13) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L596) Preprocessing directives of the forms # ifdef [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]") [*group*](cpp.pre#nt:group "15.1 Preamble [cpp.pre]")opt # ifndef [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]") [*group*](cpp.pre#nt:group "15.1 Preamble [cpp.pre]")opt # elifdef [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]") [*group*](cpp.pre#nt:group "15.1 Preamble [cpp.pre]")opt # elifndef [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1 Preamble [cpp.pre]") [*group*](cpp.pre#nt:group "15.1 Preamble [cpp.pre]")opt check whether the identifier is or is not currently defined as a macro name[.](#13.sentence-1) Their conditions are equivalent to#if defined [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"),#if !defined [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"),#elif defined [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"), and#elif !defined [*identifier*](lex.name#nt:identifier "5.11 Identifiers [lex.name]"), respectively[.](#13.sentence-2) [14](#14) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L616) Each directive's condition is checked in order[.](#14.sentence-1) If it evaluates to false (zero), the group that it controls is skipped: directives are processed only through the name that determines the directive in order to keep track of the level of nested conditionals; the rest of the directives' preprocessing tokens are ignored, as are the other preprocessing tokens in the group[.](#14.sentence-2) Only the first group whose control condition evaluates to true (nonzero) is processed; any following groups are skipped and their controlling directives are processed as if they were in a group that is skipped[.](#14.sentence-3) If none of the conditions evaluates to true, and there is a#elsedirective, the group controlled by the#else is processed; lacking a#else directive, all the groups until the#endifare skipped[.](#14.sentence-4)[124](#footnote-124 "As indicated by the syntax, a preprocessing token cannot follow a #else or #endif directive before the terminating new-line character. However, comments can appear anywhere in a source file, including within a preprocessing directive.") [15](#15) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L654) [*Example [1](#example-1)*: This demonstrates a way to include a library optional facility only if it is available:#if __has_include()# include # if __cpp_lib_optional >= 201603# define have_optional 1# endif#elif __has_include()# include # if __cpp_lib_experimental_optional >= 201411# define have_optional 1# define experimental_optional 1# endif#endif#ifndef have_optional# define have_optional 0#endif — *end example*] [16](#16) [#](http://github.com/Eelis/draft/tree/9adde4bc1c62ec234483e63ea3b70a59724c745a/source/preprocessor.tex#L677) [*Example [2](#example-2)*: This demonstrates a way to use the attribute [[acme​::​deprecated]] only if it is available[.](#16.sentence-1) #if __has_cpp_attribute(acme::deprecated)# define ATTR_DEPRECATED(msg) [[acme::deprecated(msg)]]#else# define ATTR_DEPRECATED(msg) [[deprecated(msg)]]#endif ATTR_DEPRECATED("This function is deprecated") void anvil(); — *end example*] [123)](#footnote-123)[123)](#footnoteref-123) Because the controlling constant expression is evaluated during translation phase 4, all identifiers either are or are not macro names — there simply are no keywords, enumeration constants, etc[.](#footnote-123.sentence-1) [124)](#footnote-124)[124)](#footnoteref-124) As indicated by the syntax, a preprocessing token cannot follow a#else or#endif directive before the terminating new-line character[.](#footnote-124.sentence-1) However, comments can appear anywhere in a source file, including within a preprocessing directive[.](#footnote-124.sentence-2)