Doc. No.: | N2101 |
---|---|
Date: | 2016-10-19 |
Reply to: | Clark Nelson |
__has_include
for CThis paper describes a feature that C++ has accepted for publication in the 2017 standard. It arose from work that was done by WG21's Feature-test study group; for more information and background, see:
https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations
WG14 should consider adding this to the next C standard, if only in the spirit of keeping the preprocessor synchronized between the two languages.
In terms of implementation difficulty, parsing this certainly represents some effort, but otherwise it is believed to be nearly trivial, and it can be generally useful in adapting to different translation environments.
It is worth noting that the spelling of this feature
is the subject of an NB comment against the C++17 CD;
it has been suggested that instead of __has_include
(with two initial underscores)
it should be has__include
(with two adjacent underscores).
(In C++, every identifier with adjacent underscores,
even non-initially, is reserved for the implementation.)
These changes are those that were applied to the C++17 WD, revised locally and mostly mechanically to better match the conventions of the C standard. Further editorial work is no doubt required, but I didn't want to undertake deeper revisions without getting feedback first.
Replace paragraph 1 of 6.10.1 with several paragraphs, as follows:
Syntax
- defined-macro-expression:
defined
identifierdefined (
identifier)
- h-preprocessing-token:
- any preprocessing-token other than
>
- h-pp-tokens:
- h-preprocessing-token
- h-pp-tokens h-preprocessing-token
- has-include-expression:
__has_include ( <
h-char-sequence> )
__has_include ( "
q-char-sequence" )
__has_include (
string-literal)
__has_include ( <
h-pp-tokens> )
Constraints
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;166) and it may contain zero or more defined-macro expressions and/or has-include expressions as unary operator expressions.
of the form
defined
identifier
or
defined (
identifier)
which evaluateA defined-macro expression evaluates to1
if the identifier is currently defined as a macro name (that is, if it is predefined or if 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.The third and fourth forms of has-include expression are considered only if neither of the first or second forms matches, 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 expression is searched for as if that preprocessing token sequence were the preprocessing 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 to1
if the search for the source file succeeds, and to0
if the search fails.The
#ifdef
and#ifndef
directives, and thedefined
conditional inclusion operator, shall treat__has_include
as if it were the name of a defined macro. The identifier__has_include
shall not appear in any context not mentioned in this section.
Change 16.1p4:
... After all replacements due to macro expansion andtheevaluations of defined-macro expressions and has-include expressions have been performed, all remaining identifiers and keywords, are replaced with the pp-numberdefined
unary operator0
, and then each preprocessing token is converted into a token. ...
OPTIONAL: Add the following example after 16.1p6:
EXAMPLE This demonstrates a way to include a library
optional
facility only if it is available.#if __has_include(<optional>) # include <optional> # define have_optional 1 #elif __has_include(<experimental/optional>) # include <experimental/optional> # define have_optional 1 # define experimental_optional 1 #else # define have_optional 0 #endif