328 lines
19 KiB
Markdown
328 lines
19 KiB
Markdown
[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)<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.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 <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.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(<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)
|