[cpp.cond] (original) (raw)

15 Preprocessing directives [cpp]

15.2 Conditional inclusion [cpp.cond]

defined-macro-expression: defined identifier defined ( identifier )

h-preprocessing-token: any preprocessing-token other than >

h-pp-tokens: h-preprocessing-token h-pp-tokens h-preprocessing-token

header-name-tokens: string-literal < h-pp-tokens >

has-include-expression: _­_­has_­include ( header-name ) _­_­has_­include ( header-name-tokens )

has-attribute-expression: _­_­has_­cpp_­attribute ( pp-tokens )

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 below142and it may contain zero or more defined-macro-expressions and/orhas-include-expressions and/orhas-attribute-expressions as unary operator expressions.

A defined-macro-expression evaluates to 1if 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]), for example because it has been the subject of a#definepreprocessing directive without an intervening#undefdirective with the same subject identifier), 0 if it is not.

The second form of has-include-expressionis considered only if the first form does not match, in which case the preprocessing tokens are processed just as in normal text.

The header or source file identified by the parenthesized preprocessing token sequence in each contained has-include-expressionis searched for as if that preprocessing token sequence were the pp-tokens in a #include directive, except that no further macro expansion is performed.

If such a directive would not satisfy the syntactic requirements of a #include directive, the program is ill-formed.

The has-include-expression evaluates to 1 if the search for the source file succeeds, and to 0 if the search fails.

For an attribute specified in this document, the value of the has-attribute-expressionis given by Table 18.

For other attributes recognized by the implementation, the value isimplementation-defined.

[ Note

:

It is expected that the availability of an attribute can be detected by any non-zero result.

end note

]

Table 18: _­_­has_­cpp_­attribute values [tab:cpp.cond.ha]

Attribute Value
carries_­dependency 200809L
deprecated 201309L
fallthrough 201603L
likely 201803L
maybe_­unused 201603L
no_­unique_­address 201803L
nodiscard 201907L
noreturn 200809L
unlikely 201803L

The #ifdef and #ifndef directives, and the defined conditional inclusion operator, shall treat _­_­has_­include and _­_­has_­cpp_­attributeas if they were the names of defined macros.

The identifiers _­_­has_­include and _­_­has_­cpp_­attributeshall not appear in any context not mentioned in this subclause.

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.

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 thedefinedunary operator), just as in normal text.

If the tokendefinedis generated as a result of this replacement process or use of thedefinedunary operator does not match one of the two specified forms prior to macro replacement, the behavior is undefined.

After all replacements due to macro expansion and evaluations ofdefined-macro-expressions,has-include-expressions, andhas-attribute-expressions have been performed, all remaining identifiers and keywords, except fortrueandfalse, are replaced with the pp-number 0, and then each preprocessing token is converted into a token.

[ Note

:

An alternative token is not an identifier, even when its spelling consists entirely of letters and underscores.

Therefore it is not subject to this replacement.

end note

]

The resulting tokens comprise the controlling constant expression which is evaluated according to the rules of [expr.const]using arithmetic that has at least the ranges specified in [support.limits].

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]).

[ Note

:

Thus on an implementation where std​::​numeric_­limits<int>​::​max() is 0x7FFFand std​::​numeric_­limits<unsigned int>​::​max() is 0xFFFF, the integer literal 0x8000 is signed and positive within a #ifexpression even though it is unsigned in translation phase 7.

end note

]

This includes interpreting character-literals, which may involve converting escape sequences into execution character set members.

Whether the numeric value for these character-literals matches the value obtained when an identical character-literaloccurs in an expression (other than within a#ifor#elifdirective) is implementation-defined.

[ Note

:

Thus, the constant expression in the following#ifdirective andif statement ([stmt.if]) is not guaranteed to evaluate to the same value in these two contexts:

#if 'z' - 'a' == 25 if ('z' - 'a' == 25)

end note

]

Also, whether a single-character character-literal may have a negative value is implementation-defined.

Each subexpression with typeboolis subjected to integral promotion before processing continues.

Each directive's condition is checked in order.

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.

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.

If none of the conditions evaluates to true, and there is a#else directive, the group controlled by the#elseis processed; lacking a#elsedirective, all the groups until the#endif are skipped.143

[ Example

:

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(<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

]

[ Example

:

This demonstrates a way to use the attribute [[acme​::​deprecated]]only if it is available.

#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

]