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

  1. Introduction
  2. Wording
    1. Testing for the presence of an attribute: __has_cpp_attribute
    2. Feature-testing macros
  3. Feedback question on RTTI and exceptions
  4. Revision history

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:

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 names of a defined macros. The identifiers __has_include and __has_cpp_attribute shall not appear in any context not mentioned in this subclause.

Table ? - __has_cpp_attribute values
AttributeValue
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

Date Document Description
2018-02-09 P0941R0 Initial draft
2018-05-04 P0941R1 Draft wording, with non-standard content removed and rtti/exception macros made a separate point looking for feedback.
2018-06-08 P0941R2 Removed __cpp_rtti and __cpp_exceptions. Moved and rewrote proposed wording. Used separate tables for attributes, core macros, and library macros. Sorted tables by attribute/macro name. Added new attributes approved in Jacksonville meeting. Removed duplicate entries for macros. Fixed header for __cpp_lib_tuple_element_t. Added <tuple> header for __cpp_lib_tuples_by_type. Updated value for __cpp_deduction_guides.