Feature-testing recommendations for C++

Preface

The more time that passes without any sort of feature-testing recommendation, the
more confusion will affect programmers and implementers interested in features of
C++14, of the sort that has plagued C++11 for years. So whatever action should be
taken in this arena should not be delayed any more than can be avoided.

SG10 intends to produce its recommendations solely as a WG21 document, without any
balloting at higher levels. This is partly to save time, but also to avoid making
significant conformance changes. It is hoped that compiler and library implementers
will follow these recommendations voluntarily, even without the threat of claims
of non-conformance. To improve the chances of that happening, it is considered important
to have a record of the endorsement of WG21 – or at least of the C++ technical
experts who attend WG21 meetings.

So SG10 would like to bring this document forward for some sort of approval vote
at the Chicago meeting. Formally speaking, no action by the committee is requested,
so this vote should probably be just a straw poll.

It should be understood that section 2, “Recommendations” (excluding
the sub-sections that are currently stubs), is the section for which approval and
stability really matter. Improving the examples, or explanations of rationale, is
basically editorial, and improvements will hopfully continue to happen after the
recommendations themselves have been approved.

Note that this document recommends that the __has_include feature be
provided in the C++14 time frame, even though it is not included in the CD for C++14.
A conceivable alternative would be to add __has_include to C++14 before
its final publication.

This revision of this document contains STUBS for sections expected
to be filled in later.

Explanation and rationale for the approach

Problem statement

The pace of innovation in the standardization of C++ makes long-term stability of
implementations unlikely. Features are added to the language because programmers
want to use those features. Features are added to (the working draft of) the standard
as the features become well-specified. In many cases a feature is added to an implementation
well before or well after the standard officially introducing it is approved.

This process makes it difficult for programmers who want to use a feature to know
whether it is available in any given implementation. Implementations rarely leap
from one formal revision of the standard directly to the next; the implementation
process generally proceeds by smaller steps. As a result, testing for a specific
revision of the standard (e.g. by examining the value of the __cplusplus
macro) often gives the wrong answer. Implementers generally don't want to appear
to be claiming full conformance to a standard revision until all of its features
are implemented. That leaves programmers with no portable way to determine which
features are actually available to them.

It is often possible for a program to determine, in a manner specific to a single
implementation, what features are supported by that implementation; but the means
are often poorly documented and ad hoc, and sometimes complex – especially
when the availability of a feature is controlled by an invocation option. To make
this determination for a variety of implementations in a single source base is complex
and error-prone.

Status quo

Here is some code that attempts to determine whether rvalue references are available
in the implementation in use:

First, the GNU and Microsoft version numbers are checked to see if they are high
enough. But then a check is made of the EDG version number, since that front end
also has compatibility modes for both those compilers, and defines macros indicating
(claimed) compatibility with them. If the feature wasn't implemented in the indicated
EDG version, it is assumed that the feature is not available – even though
it is possible for a customer of EDG to implement a feature before EDG does.

Fortunately Clang has ways to test specifically for the presence of specific features.
But unfortunately, the function-call-like syntax used for such tests won't work
with a standard preprocessor, so this fine new feature winds up adding its own flavor
of complexity to the mix.

Also note that this code is only the beginning of a real-world solution. A complete
solution would need to take into account more compilers, and also command-line option
settings specific to various compilers.

Characteristics of the proposed solution

To preserve implementers' freedom to add features in the order that makes the most
sense for themselves and their customers, implementers should indicate the availability
of each separate feature by adding a definition of a macro with the name corresponding
to that feature.

Important note: By recommending the use of these macros, WG21 is
not making any feature optional; the absence of a definition for
the relevant feature-test macro does not make an implementation that lacks a feature
conform to a standard that requires the feature. However, if implementers and programmers
follow these recommendations, portability of code between real-world implementations
should be improved.

To a first approximation, a feature is identified by the WG21 paper in which it is
specified, and by which it is introduced into the working draft of the standard.
Not every paper introduces a new feature worth a feature-test macro, but every paper
that is not just a collection of issue resolutions is considered a candidate; exceptions
are explicitly justified.

For C++14, it is preferred for the feature-test macro to be named using some combination
of words from the title of the paper. In the future, it is hoped that every paper
will include its own recommendations concerning feature-test macro names.

The value specified for a feature-test macro is based on the year and month in which
the feature is voted into the working draft. In a case where a feature is subsequently
changed in a significant way, but arguably remains the same feature, the value of
the macro can be changed to indicate the “revision level” of the specification
of the feature. However, in most cases it is expected that the presence of a feature
can be determined by the presence of any non-zero macro value; for example:

To avoid the user's namespace, names of macros for language features are prefixed
by “__cpp_”; for library features, by “__cpp_lib_”.
A library feature that doesn't introduce a new header is expected to be defined
by the header(s) that implement the feature.

Recommendations

Introduction

For the sake of improved portability between partial implementations of various C++
standards, WG21 (the ISO technical committee for the C++ programming language) recommends
that implementers and programmers follow the guidelines in this document concerning
feature-test macros.

Implementers who provide a new standard feature should define a macro with the recommended
name and value, in the same circumstances under which the feature is available (for
example, taking into account relevant command-line options), to indicate the presence
of support for that feature.

Programmers who wish to determine whether a feature is available in an implementation
should base that determination on the state of the macro with the recommended name.
(The absence of a tested feature may result in a program with decreased functionality,
or the relevant functionality may be provided in a different way. A program that
strictly depends on support for a feature can just try to use the feature unconditionally;
presumably, on an implementation lacking necessary support, translation will fail.)

Testing for the presence of a header: __has_include

It is impossible for a C++ program to directly, reliably and portably determine whether
or not a library header is available for inclusion. Conditionally including a header
requires the use of a configuration macro, whose setting can be determined by a
configuration-test process at build time (reliable, but less portable), or by some
other means (often not reliable or portable).

To solve this general problem, WG21 recommends that implementers provide, and programmers
use, the __has_include feature.

Syntax

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 (header-name)

__has_include (string-literal)

__has_include ( <h-pp-tokens> )

Semantics

In the first form of the has-include-expression, the parenthesized
header-name token is not subject to macro expansion. The second and third
forms are considered only if the first form does not match, and the preprocessing
tokens are processed just as in normal text.

A has-include-expression shall appear only in the controlling constant
expression of a #if or #elif directive ([cpp.cond] 16.1).
Prior to the evaluation of such an expression, the 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 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
is replaced by the pp-number1 if the search for the source
file succeeds, and by the pp-number0 if the search fails.

The #ifdef and #ifndef directives, and the defined
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.

Example

This demonstrates a way to include the header <optional> only
if it is available.

C++14 features

The following table itemizes all the changes that were made to the working draft
for C++14 as specified in a WG21 technical document. (Changes that were made as
specified in a core or library issue are not included.)

The table is sorted by the section of the standard primarily affected. The “Doc.
No.” column links to the paper itself on the committee web site. The “Macro
Name” column links to the relevant portion of the “Detailed explanation
and rationale” section of this document.

These papers just add constexpr to the declarations of several dozen
library functions in various headers. It is not clear that a macro to test for the
presence of these changes would be sufficiently useful to be worthwhile.

This paper contained the wording changes to resolve a core issue. It did not introduce
a new feature, so no macro is considered necessary.

N3638: Return type deduction for normal functions

This paper describes two separate features: the ability to deduce the return type
of a function from the return statements contained in its body, and the ability
to use decltype(auto). These features can be implemented independently,
so a macro is recommended for each.

N3639: Runtime-sized arrays with automatic storage duration

N3642: User-defined Literals for Standard Library Types

This paper specifies user-defined literal operators for two different standard library
types, which could be implemented independently. Furthermore, user-defined literal
operators are expected to be added later for at least one other library type. So
for consistency and flexibility, each type is given its own macro.

Examples:

N3644: Null Forward Iterators

Example:

N3648: Wording Changes for Generalized Lambda-capture

Example:

N3649: Generic (Polymorphic) Lambda Expressions

Example:

N3651: Variable Templates

The major change proposed by this paper is considered to be strictly a further development
of the constexpr feature of C++11. Consequently, the recommendation
here is to give an increased value to the macro indicating C++11 support for constexpr.

Example:

N3653: Member initializers and aggregates

Example:

N3654: Quoted Strings Library Proposal

Example:

N3655: TransformationTraits Redux

Example:

N3656: make_unique

N3658: Compile-time integer sequences

Example:

N3659: Shared locking in C++

Example:

N3662: C++ Dynamic Arrays

For new headers, we have a long-term solution that uses __has_include.
There was not sufficient support and a number of objections against adding macros
to existing library header files, as there was not consensus on a place to put them.

There is also a simple workaround for users that are not using libraries that define
the header file: supplying their own header that is further down the search path
than the library headers.