Date: 2013-06-04
Reply to: Clark Nelson
Title: Feature testing recommendations for C++

Feature testing recommendations for C++

Contents

  1. Explanation and rationale for the approach
    1. Problem statement
    2. Characteristics of the proposed solution
  2. Recommendations
    1. Introduction
    2. C++14 features
    3. C++11 features
    4. Conditionally-supported constructs

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.

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

#if __cpp_binary_literals
int const packed_zero_to_three = 0b00011011;
#else
int const packed_zero_to_three = 0x1B;
#endif

Note: There are cases where the decision between adding a new macro and changing the value of an existing macro will be subjective; constexpr is a good 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.

Note: Whether macros for language features and new library headers should be specified as predefined or defined in a new header is still under discussion.

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 feature should define a macro with the recommended name, 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; on an implementation lacking necessary support, translation will presumably fail.)

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.

Significant changes to C++14
Doc. No. Title Primary Section Macro name
Singular vs. plural consistency
Value Header
N3472 Binary Literals in the C++ Core Language 2.14 __cpp_binary_literals 201304 predefined
N3323 A Proposal to Tweak Certain C++ Contextual Conversions 4 __cpp_contextual_conversions 201210 predefined
N3648 Wording Changes for Generalized Lambda-capture 5.1 __cpp_generalized_capture
__cpp_init_capture
201304 predefined
N3649 Generic (Polymorphic) Lambda Expressions 5.1 __cpp_generic_lambda 201304 predefined
N3664 Clarifying Memory Allocation 5.3 Relaxation of a restriction on implementations, not a new feature; no macro needed.
N3624 Core Issue 1512: Pointer comparison vs qualification conversions 5.9, 5.10 Core issue fix, not a feature; no macro needed
N3652 Relaxing constraints on constexpr functions / constexpr member functions and implicit const 5.19, 7.1 __cpp_relaxed_constexpr
__cpp_constexpr_iteration
__cpp_constexpr_2014
__cpp_constexpr
201304 predefined
N3638 Return type deduction for normal functions 7.1 __cpp_decltype_auto 201304 predefined
__cpp_return_type_deduction 201304 predefined
N3639 Runtime-sized arrays with automatic storage duration 8.3 __cpp_runtime_array 201304 predefined
N3653 Member initializers and aggregates 8.5 __cpp_aggregate_nsdmi 201304 predefined
N3667 Drafting for Core 1402 12.8 Core issue fix, not a feature; no macro needed
N3651 Variable Templates 14, 14.7 __cpp_variable_templates 201304 predefined
N3669 Fixing constexpr member functions without const various Library fix, not a feature; no macro needed
N3673 C++ Library Working Group Ready Issues Bristol 2013 various Library issue fixes, not a feature; no macro needed
N3471 Constexpr Library Additions: utilities 20.2-20.4 __cpp_lib_constexpr_functions 201210 <utility>
N3469 Constexpr Library Additions: chrono 20.11 <chrono>
N3470 Constexpr Library Additions: containers 23.3 <array>
N3658 Compile-time integer sequences 20 __cpp_lib_integer_sequence 201304 <utility>
N3668 exchange() utility function 20 __cpp_lib_exchange_function 201304 <utility>
N3670 Wording for Addressing Tuples by Type 20.2-20.4 __cpp_lib_tuples_by_type 201304 <utility>
N3672 A proposal to add a utility class to represent optional objects 20.5 __cpp_lib_header_optional 201304 predefined
How to handle new headers?
N3656 make_unique 20.7 __cpp_lib_make_unique 201304 <memory>
N3421 Making Operator Functors greater<> 20.8 __cpp_lib_operator_functors
__cpp_lib_transparent_operators
201210 <functional>
N3462 std::result_of and SFINAE 20.9 __cpp_lib_result_of_sfinae 201210 <functional>
N3545 An Incremental Improvement to integral_constant 20.9 __cpp_lib_improved_integral_constant 201304 <type_traits>
N3655 TransformationTraits Redux 20.9 __cpp_lib_transformation_trait_aliases 201304 <type_traits>
N3642 User-defined Literals for Standard Library Types 20.11, 21.7 __cpp_lib_type_udls 201304 <string>
<chrono>
N3662 C++ Dynamic Arrays 23.2, 23.3 __cpp_lib_header_dynarray 201304 predefined
How to handle new headers?
N3657 Adding heterogeneous comparison lookup to associative containers 23.4 __cpp_lib_heterogeneous_comparison
__cpp_lib_generic_associative_lookup
201304 <map>
<set>
N3644 Null Forward Iterators 24.2 __cpp_lib_null_iterators 201304 <iterator>
N3671 Making non-modifying sequence operations more robust 25.2 __cpp_lib_robust_sequences
Is this name optimal?
201304 <algorithm>
N3654 Quoted Strings Library Proposal 27.7 __cpp_lib_quoted_string_io 201304 <iomanip>
N3659 Shared locking in C++ 30.4 __cpp_lib_shared_locking 201304 <mutex>

C++11 features

This table is not intended to be formally complete; it is intended only to cover variations of current (as of 2013) commercial importance.

Significant features of C++11
Doc. No. Title Primary Section Macro name Value Header
N2249 New Character Types in C++ 2.13 __cpp_new_character_types 200704 predefined
N2442 Raw and Unicode String Literals Unified Proposal 2.13 __cpp_raw_literals
__cpp_raw_strings
200710 predefined
__cpp_unicode_literals
__cpp_unicode_strings
200710 predefined
N2765 User-defined Literals 2.13, 13.5 __cpp_user_defined_literals 200809 predefined
N2235 Generalized Constant Expressions 5.19, 7.1 __cpp_generalized_constant
__cpp_constexpr
200704 predefined
N2343 Decltype 7.1 __cpp_decltype 200707 predefined
N2761 Towards support for attributes in C++ 7.6 __cpp_attributes 200809 predefined
N2118 A Proposal to Add an Rvalue Reference to the C++ Language 8.3 __cpp_rvalue_reference 200610 predefined
N2242 Proposed Wording for Variadic Templates 8.3, 14 __cpp_variadic_templates 200704 predefined

Conditionally-supported constructs

The standard requires implementations to document the conditionally-supported constructs it does not support. For consistency, the recommendation is to define a macro for each conditionally-supported construct that is diagnosed (not supported)

Reference Description Macro name
2.9p2 The appearance of either of the characters or \ or of either of the character sequences /* or // in a q-char-sequence or an h-char-sequence is conditionally supported with implementation-defined semantics, as is the appearance of the character " in an h-char-sequence. __cond_no_weird_header_names
2.14.3p1 A multicharacter literal, or an ordinary character literal containing a single c-char not representable in the execution character set, is conditionally-supported, has type int, and has an implementation-defined value. __cond_no_multicharacter_literals
2.14.3p3 Escape sequences in which the character following the backslash is not listed in Table 7 are conditionally-supported, with implementation-defined semantics. Probably no single macro would make sense for this.
2.14.5p13 Any other concatenations are conditionally supported with implementation-defined behavior. Probably no single macro would make sense for this.
5.2.2p7 Passing a potentially-evaluated argument of class type (Clause 9) having a nontrivial copy constructor, a non-trivial move constructor, or a non-trivial destructor, with no corresponding parameter, is conditionally-supported with implementation-defined semantics. __cond_no_passing_non_pod_by_ellipsis
5.2.10p8 Converting a function pointer to an object pointer type or vice versa is conditionally-supported. __cond_no_fun_obj_ptr_conversion
7.4p1 The asm declaration is conditionally-supported; its meaning is implementation-defined. __cond_no_asm_declaration
7.5p2 Use of a string-literal other than "C" or "C++" is conditionally-supported, with implementation-defined semantics. Probably no single macro would make sense for this.
7.6.1p3 The use of an attribute-scoped-token is conditionally-supported, with implementation-defined behavior. _cond_no_attribute_scoped_token
14p4 Use of a linkage specification other than C or C++ with any of these constructs is conditionally-supported, with implementation-defined semantics. _cond_no_template_linkage_spec