Files
2025-10-25 03:02:53 +03:00

328 lines
19 KiB
Markdown
Raw Permalink Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

[cpp.cond]
# 15 Preprocessing directives [[cpp]](./#cpp)
## 15.2 Conditional inclusion [cpp.cond]
[defined-macro-expression:](#nt:defined-macro-expression "15.2Conditional inclusion[cpp.cond]")
defined [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]")
defined ( [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") )
[h-preprocessing-token:](#nt:h-preprocessing-token "15.2Conditional inclusion[cpp.cond]")
any [*preprocessing-token*](lex.pptoken#nt:preprocessing-token "5.5Preprocessing tokens[lex.pptoken]") other than >
[h-pp-tokens:](#nt:h-pp-tokens "15.2Conditional inclusion[cpp.cond]")
[*h-preprocessing-token*](#nt:h-preprocessing-token "15.2Conditional inclusion[cpp.cond]") [*h-pp-tokens*](#nt:h-pp-tokens "15.2Conditional inclusion[cpp.cond]")opt
[header-name-tokens:](#nt:header-name-tokens "15.2Conditional inclusion[cpp.cond]")
[*string-literal*](lex.string#nt:string-literal "5.13.5String literals[lex.string]")
< [*h-pp-tokens*](#nt:h-pp-tokens "15.2Conditional inclusion[cpp.cond]") >
[has-include-expression:](#nt:has-include-expression "15.2Conditional inclusion[cpp.cond]")
__has_include ( [*header-name*](lex.header#nt:header-name "5.6Header names[lex.header]") )
__has_include ( [*header-name-tokens*](#nt:header-name-tokens "15.2Conditional inclusion[cpp.cond]") )
[has-embed-expression:](#nt:has-embed-expression "15.2Conditional inclusion[cpp.cond]")
__has_embed ( [*header-name*](lex.header#nt:header-name "5.6Header names[lex.header]") [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[cpp.pre]")opt )
__has_embed ( [*header-name-tokens*](#nt:header-name-tokens "15.2Conditional inclusion[cpp.cond]") [*pp-balanced-token-seq*](cpp.pre#nt:pp-balanced-token-seq "15.1Preamble[cpp.pre]")opt )
[has-attribute-expression:](#nt:has-attribute-expression "15.2Conditional inclusion[cpp.cond]")
__has_cpp_attribute ( [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[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.2Conditional inclusion[cpp.cond]")*s*,[*has-include-expression*](#nt:has-include-expression "15.2Conditional inclusion[cpp.cond]")*s*,[*has-attribute-expression*](#nt:has-attribute-expression "15.2Conditional inclusion[cpp.cond]")*s*,
and/or [*has-embed-expression*](#nt:has-embed-expression "15.2Conditional inclusion[cpp.cond]")*s* as unary operator expressions[.](#1.sentence-1)
A [*defined-macro-expression*](#nt:defined-macro-expression "15.2Conditional inclusion[cpp.cond]") shall not appear
within a [*has-include-expression*](#nt:has-include-expression "15.2Conditional inclusion[cpp.cond]") or [*has-embed-expression*](#nt:has-embed-expression "15.2Conditional 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.2Conditional 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.6Header 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.2Conditional inclusion[cpp.cond]") is searched for as if that preprocessing token sequence
were the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[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.6Header names[lex.header]") or cannot be combined ([[cpp.include]](cpp.include "15.3Source file inclusion")) into a single[*header-name*](lex.header#nt:header-name "5.6Header names[lex.header]") preprocessing token, the program is ill-formed[.](#3.sentence-2)
The [*has-include-expression*](#nt:has-include-expression "15.2Conditional 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.2Conditional inclusion[cpp.cond]") is processed as if that
preprocessing token sequence were the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[cpp.pre]") of a #embed directive ([[cpp.embed]](cpp.embed "15.4Resource inclusion")),
except that no further macro expansion is performed[.](#4.sentence-1)
The [*has-embed-expression*](#nt:has-embed-expression "15.2Conditional 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.1Preamble[cpp.pre]")*s* in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1Preamble[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.1Preamble[cpp.pre]")*s* in the [*embed-parameter-seq*](cpp.pre#nt:embed-parameter-seq "15.1Preamble[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.1Preamble[cpp.pre]") in an [*has-embed-expression*](#nt:has-embed-expression "15.2Conditional 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.2Conditional inclusion[cpp.cond]") is replaced by
a non-zero [*pp-number*](lex.ppnumber#nt:pp-number "5.7Preprocessing numbers[lex.ppnumber]") matching the form of an [*integer-literal*](lex.icon#nt:integer-literal "5.13.2Integer literals[lex.icon]") if the implementation supports an attribute
with the name specified by interpreting
the [*pp-tokens*](cpp.pre#nt:pp-tokens "15.1Preamble[cpp.pre]"), after macro expansion,
as an [*attribute-token*](dcl.attr.grammar#nt:attribute-token "9.13.1Attribute 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.1Preamble[cpp.pre]") do not match the form of an [*attribute-token*](dcl.attr.grammar#nt:attribute-token "9.13.1Attribute 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.2Conditional 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)<br>**Attribute** | **Value** |
| --- | --- |
| [🔗](#tab:cpp.cond.ha-row-2)<br>assume | 202207L |
| [🔗](#tab:cpp.cond.ha-row-3)<br>deprecated | 201309L |
| [🔗](#tab:cpp.cond.ha-row-4)<br>fallthrough | 201603L |
| [🔗](#tab:cpp.cond.ha-row-5)<br>indeterminate | 202403L |
| [🔗](#tab:cpp.cond.ha-row-6)<br>likely | 201803L |
| [🔗](#tab:cpp.cond.ha-row-7)<br>maybe_unused | 201603L |
| [🔗](#tab:cpp.cond.ha-row-8)<br>no_unique_address | 201803L |
| [🔗](#tab:cpp.cond.ha-row-9)<br>nodiscard | 201907L |
| [🔗](#tab:cpp.cond.ha-row-10)<br>noreturn | 200809L |
| [🔗](#tab:cpp.cond.ha-row-11)<br>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.10Tokens[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.7Constant expressions[expr.const]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[cpp.pre]") [*group*](cpp.pre#nt:group "15.1Preamble[cpp.pre]")opt
# elif [*constant-expression*](expr.const#nt:constant-expression "7.7Constant expressions[expr.const]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[cpp.pre]") [*group*](cpp.pre#nt:group "15.1Preamble[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.11Identifiers[lex.name]")*s*limit, prefix, suffix, or if_empty and that [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") is defined
as a macro ([[cpp.replace.general]](cpp.replace.general "15.7.1General")), 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.2Conditional inclusion[cpp.cond]")*s*,[*has-include-expression*](#nt:has-include-expression "15.2Conditional inclusion[cpp.cond]")*s*,[*has-embed-expression*](#nt:has-embed-expression "15.2Conditional inclusion[cpp.cond]")*s*, and[*has-attribute-expression*](#nt:has-attribute-expression "15.2Conditional 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.7Preprocessing 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.9Alternative 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.7Constant expressions") using arithmetic that has at least the ranges specified
in [[support.limits]](support.limits "17.3Implementation 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.1Header <cstdint> synopsis"))[.](#12.sentence-2)
[*Note [4](#note-4)*:
Thus on an
implementation where std::numeric_limits<int>::max() is 0x7FFF and std::numeric_limits<unsigned int>::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.2Phases of translation[lex.phases]")[.](#12.sentence-3)
— *end note*]
This includes interpreting [*character-literal*](lex.ccon#nt:character-literal "5.13.3Character literals[lex.ccon]")*s* according to the rules in [[lex.ccon]](lex.ccon "5.13.3Character 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.11Identifiers[lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[cpp.pre]") [*group*](cpp.pre#nt:group "15.1Preamble[cpp.pre]")opt
# ifndef [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[cpp.pre]") [*group*](cpp.pre#nt:group "15.1Preamble[cpp.pre]")opt
# elifdef [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[cpp.pre]") [*group*](cpp.pre#nt:group "15.1Preamble[cpp.pre]")opt
# elifndef [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]") [*new-line*](cpp.pre#nt:new-line "15.1Preamble[cpp.pre]") [*group*](cpp.pre#nt:group "15.1Preamble[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.11Identifiers[lex.name]"),#if !defined [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]"),#elif defined [*identifier*](lex.name#nt:identifier "5.11Identifiers[lex.name]"), and#elif !defined [*identifier*](lex.name#nt:identifier "5.11Identifiers[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(<optional>)# include <optional># if __cpp_lib_optional >= 201603# define have_optional 1# endif#elif __has_include(<experimental/optional>)# include <experimental/optional># 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)