SD-6: SG10 Feature Test Recommendations

Doc. No.: P0096R2
Date: 2016-02-23
Reply to: Clark Nelson
Title: Feature-testing recommendations for C++

Feature-testing recommendations for C++

Preface

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

Contents

  1. Introduction
  2. Explanation and rationale for the approach
    1. Problem statement
    2. Status quo
    3. Characteristics of the proposed solution
  3. Recommendations
    1. Introduction
    2. Testing for the presence of a header: __has_include
    3. Testing for the presence of an attribute: __has_cpp_attribute
    4. C++17 features
    5. C++14 features
    6. C++11 features
    7. Conditionally-supported constructs (STUB)
    8. C++98 features (STUB)
    9. Features published and later removed
  4. Recommendations from Technical Specifications
  5. Detailed explanation and rationale
    1. C++14 features
    2. C++17 features
  6. Annex: Model wording for a Technical Specification
  7. Revision history

Introduction

At the September 2013 (Chicago) meeting of WG21, there was a five-way poll of all of the C++ experts in attendance – approximately 80 – concerning their support for the approach described herein for feature-testing in C++. The results of the poll:

Strongly favor Favor Neutral Oppose Strongly oppose
lots lots 1 0 0

This document was subsequently designated WG21's SD-6 (sixth standing document), which will continue to be maintained by SG10.

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:

#ifndef __USE_RVALUE_REFERENCES
  #if (__GNUC__ > 4 || __GNUC__ == 4 && __GNUC_MINOR__ >= 3) || \
      _MSC_VER >= 1600
    #if __EDG_VERSION__ > 0
      #define __USE_RVALUE_REFERENCES (__EDG_VERSION__ >= 410)
    #else
      #define __USE_RVALUE_REFERENCES 1
    #endif
  #elif __clang__
    #define __USE_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
  #else
    #define __USE_RVALUE_REFERENCES 0
  #endif
#endif

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, the feature-test macro name generally consists of 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 is 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

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. Therefore, if the most useful purpose for a feature-test macro would be to control the inclusion of a #error directive if the feature is unavailable, that is considered inadequate justification for the macro. Note that the usefulness of a test macro for a feature is completely independent of the usefulness of the feature itself.)

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-number 1 if the search for the source file succeeds, and by the pp-number 0 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 use a library optional facility only if it is available.

#ifdef __has_include
#  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
#  else
#    define have_optional 0
#  endif
#endif

Testing for the presence of an attribute: __has_cpp_attribute

A C++ program cannot directly, reliably, and portably determine whether or not a standard or vendor-specific attribute is available for use. Testing for attribute support generally requires complex macro logic, as illustrated above for language features in general.

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

Syntax

has-attribute-expression:
__has_cpp_attribute ( attribute-token )

Semantics

A has-attribute-expression shall appear only in the controlling constant expression of a #if or #elif directive ([cpp.cond] 16.1). The has-attribute-expression is replaced by a non-zero pp-number if the implementation supports an attribute with the specified name, and by the pp-number 0 otherwise.

For a standard attribute, the value of the __has_cpp_attribute macro is based on the year and month in which the attribute was voted into the working draft. In the case where the attribute is vendor-specific, the value is implementation-defined. However, in most cases it is expected that the availability of an attribute can be detected by any non-zero result.

The #ifdef and #ifndef directives, and the defined conditional inclusion operator, shall treat __has_cpp_attribute as if it were the name of a defined macro. The identifier __has_cpp_attribute shall not appear in any context not mentioned in this section.

Example

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

#ifdef __has_cpp_attribute
#  if __has_cpp_attribute(deprecated)
#    define ATTR_DEPRECATED(msg) [[deprecated(msg)]]
#  else
#    define ATTR_DEPRECATED(msg)
#  endif
#endif

C++17 features

The following table itemizes all the changes that were made to the working draft for C++17 as specified in a WG21 technical document. (Changes that were made as specified in a core or library issue are not generally 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. When the recommendation is to change the value of a macro previously recommended to be defined, the “Value” column links to the table entry for the previous recommendation.

For library features, the “Header“ column identifies the header that is expected to define the macro, although the macro may also be predefined. For language features, the macro must be predefined.

Significant changes to C++17
Doc. No. Title Primary Section Macro Name Value Header
N4086 Removing trigraphs??! 2.4 none
N4267 Adding u8 character literals 2.14 none
N4261 Proposed resolution for Core Issue 330: Qualification conversions and pointers to arrays of pointers 4.4, 5.2 none
P0012R1 Make exception specifications be part of the type system 4.12, 15.4 __cpp_noexcept_function_type 201510 predefined
N4295 Folding expressions 5.1, 14.5, 14.6 __cpp_fold_expressions 201411 predefined
P0002R1 Remove Deprecated operator++(bool) 5.3 none
N3928 Extending static_assert 7 __cpp_static_assert 201411 predefined
N3922 New Rules for auto deduction from braced-init-list 7.1 none
P0001R1 Remove Deprecated Use of the register Keyword 7.1 none
N4266 Attributes for namespaces and enumerators 7.2, 7.3 __cpp_namespace_attributes 201411 predefined
__cpp_enumerator_attributes 201411 predefined
N4230 Nested namespace definition 7.3 __cpp_nested_namespace_definitions 201411 predefined
P0136R1 Rewording inheriting constructors (core issue 1941 et al) 7.3 __cpp_inheriting_constructors 201511 predefined
P0134R0 Introducing a name for brace-or-equal-initializers for non-static data members 9.2 none
N4051 Allow typename in a template template parameter 14.1 none
N4268 Allow constant evaluation for all non-type template arguments 14.3 __cpp_nontype_template_args 201411 predefined
N4262 Wording for Forwarding References 14.8 none
N4285 Cleanup for exception-specification and throw-expression 15 none
P0061R1 __has_include for C++17 16.1 none
N4259 Wording for std::uncaught_exceptions 18.8 __cpp_lib_uncaught_exceptions 201411 <exception>
P0007R1 Constant View: A proposal for a std::as_const helper function template 20.2 __cpp_lib_as_const 201510 <utility>
N4387 Improving pair and tuple 20.3, 20.4 none 201505 <utility> <tuple>
N4190 Removing auto_ptr, random_shuffle(), And Old <functional> Stuff 20.7-20.9 none
P0074R0 Making std::owner_less more flexible 20.7 __cpp_lib_transparent_operators 201510 <memory> <functional>
N4089 Safe conversions in unique_ptr<T[]> 20.8 none
N4366 LWG 2228: Missing SFINAE rule in unique_ptr templated assignment 20.8 none
N4169 A proposal to add invoke function template 20.9 __cpp_lib_invoke 201411 <functional>
N4277 TriviallyCopyable reference_wrapper 20.9 none
N3911 TransformationTrait Alias void_t 20.10 __cpp_lib_void_t 201411 <type_traits>
N4389 Wording for bool_constant 20.10 __cpp_lib_bool_constant 201505 <type_traits>
P0006R0 Adopt Type Traits Variable Templates from Library Fundamentals TS for C++17 20.10 __cpp_lib_type_trait_variable_templates 201510 <type_traits>
P0013R1 Logical Operator Type Traits 20.10 __cpp_lib_logical_traits 201510 <type_traits>
P0092R1 Polishing <chrono> 20.12 __cpp_lib_chrono 201510 <chrono>
N4258 Cleaning-up noexcept in the Library 21.4, 23.3-23.5 __cpp_lib_allocator_traits_is_always_equal 201411 <memory> <scoped_allocator> <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set>
N4284 Contiguous Iterators 23.2, 24.2 none
N4510 Minimal incomplete type support for standard containers 23.3 __cpp_lib_incomplete_container_elements 201505 headers
N4279 Improved insertion interface for unique-key maps 23.4 __cpp_lib_map_try_emplace 201411 <map>
23.5 __cpp_lib_unordered_map_try_emplace 201411 <unordered_map>
N4280 Non-member size() and more 24.3 __cpp_lib_nonmember_container_access 201411 <iterator> <array> <deque> <forward_list> <list> <map> <regex> <set> <string> <unordered_map> <unordered_set> <vector>
N4508 A proposal to add shared_mutex (untimed) 30.4 __cpp_lib_shared_mutex 201505 <shared_mutex>
P0156R0 Variadic lock_guard 30.4 __cpp_lib_lock_guard_variadic 201510 <thread>
P0004R1 Remove Deprecated iostreams aliases D none

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 generally 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. When the recommendation is to change the value of a macro previously recommended to be defined, the “Value” column links to the table entry for the previous recommendation.

For library features, the “Header“ column identifies the header that is expected to define the macro, although the macro may also be predefined. For language features, the macro must be predefined.

Significant changes to C++14
Doc. No. Title Primary Section Macro Name Value Header
N3910 What can signal handlers do? (CWG 1441) 1.9-1.10 none
N3927 Definition of Lock-Free 1.10 none
N3472 Binary Literals in the C++ Core Language 2.14 __cpp_binary_literals 201304 predefined
N3781 Single-Quotation-Mark as a Digit Separator 2.14 __cpp_digit_separators 201309 predefined
none
N3323 A Proposal to Tweak Certain C++ Contextual Conversions 4 none
N3648 Wording Changes for Generalized Lambda-capture 5.1 __cpp_init_captures 201304 predefined
N3649 Generic (Polymorphic) Lambda Expressions 5.1 __cpp_generic_lambdas 201304 predefined
N3664 Clarifying Memory Allocation 5.3 none
N3778 C++ Sized Deallocation 5.3, 18.6 __cpp_sized_deallocation 201309 predefined
N3624 Core Issue 1512: Pointer comparison vs qualification conversions 5.9, 5.10 none
N3652 Relaxing constraints on constexpr functions / constexpr member functions and implicit const 5.19, 7.1 __cpp_constexpr 201304 predefined
N3638 Return type deduction for normal functions 7.1 __cpp_decltype_auto 201304 predefined
__cpp_return_type_deduction 201304 predefined
N3760 [[deprecated]] attribute 7.6 __has_cpp_attribute(deprecated) 201309 predefined
N3653 Member initializers and aggregates 8.5 __cpp_aggregate_nsdmi 201304 predefined
N3667 Drafting for Core 1402 12.8 none
N3651 Variable Templates 14, 14.7 __cpp_variable_templates 201304 predefined
N3669 Fixing constexpr member functions without const various none
N3673 C++ Library Working Group Ready Issues Bristol 2013 various none
N3658 Compile-time integer sequences 20 __cpp_lib_integer_sequence 201304 <utility>
N3668 exchange() utility function 20 __cpp_lib_exchange_function 201304 <utility>
N3471 Constexpr Library Additions: utilities 20.2-20.4 none
N3670 Wording for Addressing Tuples by Type 20.2-20.4 __cpp_lib_tuples_by_type 201304 <utility>
N3887 Consistent Metafunction Aliases 20.3-20.4 __cpp_lib_tuple_element_t 201402 <utility>
N3656 make_unique 20.7 __cpp_lib_make_unique 201304 <memory>
N3421 Making Operator Functors greater<> 20.8 __cpp_lib_transparent_operators 201210 <functional>
N3545 An Incremental Improvement to integral_constant 20.9 __cpp_lib_integral_constant_callable 201304 <type_traits>
N3655 TransformationTraits Redux 20.9 __cpp_lib_transformation_trait_aliases 201304 <type_traits>
N3789 Constexpr Library Additions: functional 20.10 none
N3462 std::result_of and SFINAE 20.9
20.10
__cpp_lib_result_of_sfinae 201210 <functional>
<type_traits>
LWG 2112 User-defined classes that cannot be derived from 20.10 __cpp_lib_is_final 201402 <type_traits>
LWG 2247 Type traits and std::nullptr_t 20.10 __cpp_lib_is_null_pointer 201309 <type_traits>
N3469 Constexpr Library Additions: chrono 20.11 none
N3642 User-defined Literals for Standard Library Types 20.11 __cpp_lib_chrono_udls 201304 <chrono>
21.7 __cpp_lib_string_udls 201304 <string>
N3470 Constexpr Library Additions: containers 23.3 none
N3657 Adding heterogeneous comparison lookup to associative containers 23.4 __cpp_lib_generic_associative_lookup 201304 <map>
<set>
N3644 Null Forward Iterators 24.2 __cpp_lib_null_iterators 201304 <iterator>
LWG 2285 make_reverse_iterator 24.5 __cpp_lib_make_reverse_iterator 201402 <iterator>
N3671 Making non-modifying sequence operations more robust 25.2 __cpp_lib_robust_nonmodifying_seq_ops 201304 <algorithm>
N3779 User-defined Literals for std::complex 26.4 __cpp_lib_complex_udls 201309 <complex>
N3924 Discouraging rand() in C++14 26.8 none
N3654 Quoted Strings Library Proposal 27.7 __cpp_lib_quoted_string_io 201304 <iomanip>
LWG 2249 Remove gets from <cstdio> 27.9 none
N3786 Prohibiting "out of thin air" results in C++14 29.3 none
N3659 Shared locking in C++ 30.4 __has_include(<shared_mutex>) 1 predefined
N3891 A proposal to rename shared_mutex to shared_timed_mutex 30.4 __cpp_lib_shared_timed_mutex 201402 <shared_mutex>
N3776 Wording for ~future 30.6 none

C++11 features

Significant features of C++11
Doc. No. Title Primary Section Macro name Value Header
N2249 New Character Types in C++ 2.13 __cpp_unicode_characters 200704 predefined
N2442 Raw and Unicode String Literals Unified Proposal 2.13 __cpp_raw_strings 200710 predefined
__cpp_unicode_literals 200710 predefined
N2765 User-defined Literals 2.13, 13.5 __cpp_user_defined_literals 200809 predefined
N2927 New wording for C++0x lambdas 5.1 __cpp_lambdas 200907 predefined
N2235 Generalized Constant Expressions 5.19, 7.1 __cpp_constexpr 200704 predefined
N2930 Range-Based For Loop Wording (Without Concepts) 6.5 __cpp_range_based_for 200907 predefined
N1720 Proposal to Add Static Assertions to the Core Language 7 __cpp_static_assert 200410 predefined
N2343 Decltype 7.1 __cpp_decltype 200707 predefined
N2761 Towards support for attributes in C++ 7.6 __cpp_attributes 200809 predefined
__has_cpp_attribute(noreturn) 200809 predefined
__has_cpp_attribute(carries_dependency) 200809 predefined
N2118 A Proposal to Add an Rvalue Reference to the C++ Language 8.3 __cpp_rvalue_references 200610 predefined
N2242 Proposed Wording for Variadic Templates 8.3, 14 __cpp_variadic_templates 200704 predefined
N2672 Initializer List proposed wording 8.5 __cpp_initializer_lists 200806 predefined
N1986 Delegating Constructors 12.6 __cpp_delegating_constructors 200604 predefined
N2756 Non-static data member initializers 12.6 __cpp_nsdmi 200809 predefined
N2540 Inheriting Constructors 12.9 __cpp_inheriting_constructors 200802 predefined
N2439 Extending move semantics to *this 13.3 __cpp_ref_qualifiers 200710 predefined
N2258 Template Aliases 14.5 __cpp_alias_templates 200704 predefined

Conditionally-supported constructs

STUB

C++98 features

STUB: especially for exception handling and RTTI

Feature Primary section Macro name Value Header
Run-time type identification 5.2 __cpp_rtti 199711 predefined
Exception handling 15 __cpp_exceptions 199711 predefined

Features published and later removed

Features removed from C++14

Features in the first CD of C++14, subsequently removed to a Technical Specification
Doc. No. Title Primary Section Macro Name Value Header
N3639 Runtime-sized arrays with automatic storage duration 8.3 __cpp_runtime_arrays      201304 predefined
N3672 A proposal to add a utility class to represent optional objects 20.5 __has_include(<optional>) 1 predefined
N3662 C++ Dynamic Arrays 23.2, 23.3 __has_include(<dynarray>) 1 predefined

The intention is that an implementation which provides runtime-sized arrays as specified in the first CD should define __cpp_runtime_arrays as 201304. The expectation is that a later document specifying runtime-sized arrays will specify a different value for __cpp_runtime_arrays.

Recommendations from Technical Specifications

In this section, feature-test macros from all WG21 Technical Specifications are collected, for convenience.

C++ Extensions for Library Fundamentals

The recommended macro name is "__cpp_lib_experimental_" followed by the string in the "Macro Name Suffix" column.

Doc. No. Title Primary Section Macro Name Suffix Value Header
N3915 apply() call a function with arguments from a tuple 3.2.2 apply 201402 <experimental/tuple>
N3932 Variable Templates For Type Traits 3.3.1 type_trait_variable_templates 201402 <experimental/type_traits>
N3866 Invocation type traits 3.3.2 invocation_type 201406 <experimental/type_traits>
N3916 Type-erased allocator for std::function 4.2 function_erased_allocator 201406 <experimental/functional>
N3905 Extending std::search to use Additional Searching Algorithms 4.3 boyer_moore_searching 201411 <experimental/functional>
N3672, N3793 A utility class to represent optional objects 5 optional 201411 <experimental/optional>
N3804 Any Library Proposal 6 any 201411 <experimental/any>
N3921 string_view: a non-own