Doc. No.: P0941R2 Date: 2018-06-08 Reply to: Ville Voutilainen

Jonathan Wakely

Audience: CWG, LWG

Integrating feature-test macros into the C++ WD (rev. 2)

Preface

This revision of this paper proposes incorporating feature-testing macros into the working draft of the C++ standard.

Contents

Introduction

At the November 2017 (Albuquerque) meeting of WG21, there was a five-way poll of all of the C++ experts in attendance concerning their support for "Feature macros should be standardized in the IS, and we want to invite a proposal to be reviewed by EWG to discss the rationale and granularity." The results of the poll:

Strongly favor Favor Neutral Oppose Strongly oppose 27 21 9 4 1

The approach taken here is as follows:

For the macros incorporated, use the latest value from SD-6, and do not bump the numbers. This is done in order to avoid pointless breakage of existing code that uses the SD-6 macros.

Library macros are defined both in the corresponding header for the library facility and in <version>.

Wording

Testing for the presence of an attribute: __has_cpp_attribute

In Clause [cpp.cond] add the following content:

has-include-expression : __has_include ( < h-char-sequence > ) __has_include ( " q-char-sequence " ) __has_include ( string-literal ) __has_include ( < h-pp-tokens > ) has-attribute-expression : __has_cpp_attribute ( pp-tokens ) -1- 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 and it may contain zero or more defined-macro-expressions and/or has-include-expressions and/or has-attribute-expressions as unary operator expressions. -2- A defined-macro-expression evaluates to 1 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. -3- 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. -4- 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 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. -?- Each has-attribute-expression is replaced by a non-zero pp-number matching the form of an integer-literal if the implementation supports an attribute with the name specified by interpreting the pp-tokens as an attribute-token , and by 0 otherwise. The program is ill-formed if the pp-tokens do not match the form of an attribute-token . -?- For an attribute specified in this document, the value of the has-attribute-expression is given by Table ?. For other attributes recognized by the implementation, the value is implementation-defined. [Note: It is expected that the availability of an attribute can be detected by any non-zero result. —end note] The #ifdef and #ifndef directives, and the defined conditional inclusion operator, shall treat __has_include and __has_cpp_attribute as if it they were the name s of a defined macro s . The identifier s __has_include and __has_cpp_attribute shall not appear in any context not mentioned in this subclause. Table ? - __has_cpp_attribute values Attribute Value carries_dependency 200809L deprecated 201309L fallthrough 201603L likely 201803L maybe_unused 201603L no_unique_address 201803L nodiscard 201603L noreturn 200809L unlikely 201803L

Adjust the example at the end of [cpp.cond] and add a new example:

[Example: This demonstrates a way to include a library optional facility only if it is available: #if __has_include(<optional>) # include <optional> # 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 # else #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]

Feature-testing macros

Drafting note: these are intended to match the latest values in SD-6. Wording review should check that that is indeed so.

In [cpp.predefined] add the following content and table:

-1-The following macro names shall be defined by the implementation: — __cplusplus ... — __DATE__ ... — __FILE__ ... — __LINE__ ... — __STDC_HOSTED__ ... — __STDCPP_DEFAULT_NEW_ALIGNMENT__ ... — __TIME__ ... — The names listed in Table ??. The macros defined in Table ?? shall be defined to the corresponding integer literal. [Note: Future versions of this International Standard might replace the values of these macros with greater values. —end note] Table ?? - Feature-test macros Name Value __cpp_aggregate_bases 201603L __cpp_aggregate_nsdmi 201304L __cpp_alias_templates 200704L __cpp_aligned_new 201606L __cpp_attributes 200809L __cpp_binary_literals 201304L __cpp_capture_star_this 201603L __cpp_constexpr 201603L __cpp_decltype 200707L __cpp_decltype_auto 201304L __cpp_deduction_guides 201703L __cpp_delegating_constructors 200604L __cpp_enumerator_attributes 201411L __cpp_fold_expressions 201603L __cpp_generic_lambdas 201304L __cpp_guaranteed_copy_elision 201606L __cpp_hex_float 201603L __cpp_if_constexpr 201606L __cpp_inheriting_constructors 201511L __cpp_init_captures 201304L __cpp_initializer_lists 200806L __cpp_inline_variables 201606L __cpp_lambdas 200907L __cpp_namespace_attributes 201411L __cpp_noexcept_function_type 201510L __cpp_nontype_template_args 201411L __cpp_nontype_template_parameter_auto 201606L __cpp_nsdmi 200809L __cpp_range_based_for 201603L __cpp_raw_strings 200710L __cpp_ref_qualifiers 200710L __cpp_return_type_deduction 201304L __cpp_rvalue_references 200610L __cpp_sized_deallocation 201309L __cpp_static_assert 201411L __cpp_structured_bindings 201606L __cpp_template_template_args 201611L __cpp_threadsafe_static_init 200806L __cpp_unicode_characters 200704L __cpp_unicode_literals 200710L __cpp_user_defined_literals 200809L __cpp_variable_templates 201304L __cpp_variadic_templates 200704L __cpp_variadic_using 201611L

Add the following content to [support.limits.general]:

The macros in Table ??? are defined after inclusion of the header <version> or one of the corresponding headers specified in the table. [Note: Future versions of this International Standard might replace the values of these macros with greater values. —end note] Table ??? - Standard library feature-test macros Macro name Value Headers __cpp_lib_addressof_constexpr 201603L <memory> __cpp_lib_allocator_traits_is_always_equal 201411L <memory> <scoped_allocator>

<string> <deque>

<forward_list> <list>

<vector> <map>

<set> <unordered_map>

<unordered_set> __cpp_lib_any 201606L <any> __cpp_lib_apply 201603L <tuple> __cpp_lib_array_constexpr 201603L <iterator> <array> __cpp_lib_as_const 201510L <utility> __cpp_lib_atomic_is_always_lock_free 201603L <atomic> __cpp_lib_bool_constant 201505L <type_traits> __cpp_lib_boyer_moore_searcher 201603L <functional> __cpp_lib_byte 201603L <cstddef> __cpp_lib_chrono 201611L <chrono> __cpp_lib_clamp 201603L <algorithm> __cpp_lib_complex_udls 201309L <complex> __cpp_lib_enable_shared_from_this 201603L <memory> __cpp_lib_exchange_function 201304L <utility> __cpp_lib_execution 201603L <execution> __cpp_lib_filesystem 201703L <filesystem> __cpp_lib_gcd_lcm 201606L <numeric> __cpp_lib_generic_associative_lookup 201304L <map>

<set> __cpp_lib_hardware_interference_size 201703L <new> __cpp_lib_has_unique_object_representations 201606L <type_traits> __cpp_lib_hypot 201603L <cmath> __cpp_lib_incomplete_container_elements 201505L <forwardlist>

<list> <vector> __cpp_lib_integer_sequence 201304L <utility> __cpp_lib_integral_constant_callable 201304L <type_traits> __cpp_lib_invoke 201411L <functional> __cpp_lib_is_aggregate 201703L <type_traits> __cpp_lib_is_final 201402L <type_traits> __cpp_lib_is_invocable 201703L <type_traits> __cpp_lib_is_null_pointer 201309L <type_traits> __cpp_lib_is_swappable 201603L <type_traits> __cpp_lib_launder 201606L <new> __cpp_lib_logical_traits 201510L <type_traits> __cpp_lib_make_from_tuple 201606L <tuple> __cpp_lib_make_reverse_iterator 201402L <iterator> __cpp_lib_make_unique 201304L <memory> __cpp_lib_map_try_emplace 201411L <map> __cpp_lib_math_special_functions 201603L <cmath> __cpp_lib_memory_resource 201603L <memory_resource> __cpp_lib_node_extract 201606L <map> <set> <unordered_map> <unordered_set> __cpp_lib_nonmember_container_access 201411L <iterator> <array> <deque> <forward_list>

<list> <map> <regex> <set> <string>

<unordered_map> <unordered_set> <vector> __cpp_lib_not_fn 201603L <functional> __cpp_lib_null_iterators 201304L <iterator> __cpp_lib_optional 201606L <optional> __cpp_lib_parallel_algorithm 201603L <algorithm> <numeric> __cpp_lib_quoted_string_io 201304L <iomanip> __cpp_lib_raw_memory_algorithms 201606L <memory> __cpp_lib_result_of_sfinae 201210L <functional>

<type_traits> __cpp_lib_robust_nonmodifying_seq_ops 201304L <algorithm> __cpp_lib_sample 201603L <algorithm> __cpp_lib_scoped_lock 201703L <mutex> __cpp_lib_shared_mutex 201505L <shared_mutex> __cpp_lib_shared_ptr_arrays 201611L <memory> __cpp_lib_shared_ptr_weak_type 201606L <memory> __cpp_lib_shared_timed_mutex 201402L <shared_mutex> __cpp_lib_string_udls 201304L <string> __cpp_lib_string_view 201606L <string> <string_view> __cpp_lib_to_chars 201611L <utility> __cpp_lib_transformation_trait_aliases 201304L <type_traits> __cpp_lib_transparent_operators 201510L <memory> <functional> __cpp_lib_tuple_element_t 201402L <tuple> __cpp_lib_tuples_by_type 201304L <utility> <tuple> __cpp_lib_type_trait_variable_templates 201510L <type_traits> __cpp_lib_uncaught_exceptions 201411L <exception> __cpp_lib_unordered_map_try_emplace 201411L <unordered_map> __cpp_lib_variant 201606L <variant> __cpp_lib_void_t 201411L <type_traits>

Revision history