Doc. No.: P0941R0
Date: 2018-05-04
Reply to: Ville Voutilainen
Audience: EWG, LEWG

Integrating feature-test macros into the C++ WD

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

After [lex.literal], insert a new subsection of section [lex] with the following content:

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

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.

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

#ifndef __has_cpp_attribute
# define __has_cpp_attribute(x) 0
#endif
#if __has_cpp_attribute(deprecated)
# define ATTR_DEPRECATED(msg) [[deprecated(msg)]]
#else
# define ATTR_DEPRECATED(msg)
#endif
  

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.

After [support.runtime], insert a new subsection of section [language.support] with the following content:

The macros that are not predefined are defined in the header <version> in addition to the header specified in the table.

Macro name Value Header
__cpp_unicode_characters 200704 predefined
__cpp_raw_strings 200710 predefined
__cpp_unicode_literals 200710 predefined
__cpp_user_defined_literals 200809 predefined
__cpp_threadsafe_static_init 200806 predefined
__cpp_lambdas 200907 predefined
__cpp_range_based_for 200907 predefined
__cpp_static_assert 200410 predefined
__cpp_decltype 200707 predefined
__cpp_attributes 200809 predefined
__has_cpp_attribute(noreturn) 200809 predefined
__has_cpp_attribute(carries_dependency) 200809 predefined
__cpp_rvalue_references 200610 predefined
__cpp_variadic_templates 200704 predefined
__cpp_initializer_lists 200806 predefined
__cpp_delegating_constructors 200604 predefined
__cpp_nsdmi 200809 predefined
__cpp_ref_qualifiers 200710 predefined
__cpp_alias_templates 200704 predefined
__cpp_binary_literals 201304 predefined
__cpp_init_captures 201304 predefined
__cpp_generic_lambdas 201304 predefined
__cpp_sized_deallocation 201309 predefined
__cpp_decltype_auto 201304 predefined
__cpp_return_type_deduction 201304 predefined
__has_cpp_attribute(deprecated) 201309 predefined
__cpp_aggregate_nsdmi 201304 predefined
__cpp_variable_templates 201304 predefined
__cpp_lib_integer_sequence 201304 <utility>
__cpp_lib_exchange_function 201304 <utility>
__cpp_lib_tuples_by_type 201304 <utility>
__cpp_lib_tuple_element_t 201402 <utility>
__cpp_lib_make_unique 201304 <memory>
__cpp_lib_transparent_operators 201210 <functional>
__cpp_lib_integral_constant_callable 201304 <type_traits>
__cpp_lib_transformation_trait_aliases 201304 <type_traits>
__cpp_lib_result_of_sfinae 201210 <functional>
<type_traits>
__cpp_lib_is_final 201402 <type_traits>
__cpp_lib_is_null_pointer 201309 <type_traits>
__cpp_lib_string_udls 201304 <string>
__cpp_lib_generic_associative_lookup 201304 <map>
<set>
__cpp_lib_null_iterators 201304 <iterator>
__cpp_lib_make_reverse_iterator 201402 <iterator>
__cpp_lib_robust_nonmodifying_seq_ops 201304 <algorithm>
__cpp_lib_complex_udls 201309 <complex>
__cpp_lib_quoted_string_io 201304 <iomanip>
__has_include(<shared_mutex>) 1 predefined
__cpp_lib_shared_timed_mutex 201402 <shared_mutex>
__cpp_hex_float 201603 predefined
__cpp_inline_variables 201606 predefined
__cpp_aligned_new 201606 predefined
__cpp_guaranteed_copy_elision 201606 predefined
__cpp_noexcept_function_type 201510 predefined
__cpp_fold_expressions 201411 predefined
__cpp_capture_star_this 201603 predefined
__cpp_constexpr 201603 predefined
__cpp_if_constexpr 201606 predefined
__cpp_range_based_for 201603 predefined
__cpp_static_assert 201411 predefined
__cpp_deduction_guides 201606 predefined
__cpp_deduction_guides 201611 predefined
__cpp_nontype_template_parameter_auto 201606 predefined
__cpp_namespace_attributes 201411 predefined
__cpp_enumerator_attributes 201411 predefined
__cpp_inheriting_constructors 201511 predefined
__cpp_variadic_using 201611 predefined
__has_cpp_attribute(fallthrough) 201603 predefined
__has_cpp_attribute(nodiscard) 201603 predefined
__has_cpp_attribute(maybe_unused) 201603 predefined
__cpp_structured_bindings 201606 predefined
__cpp_aggregate_bases 201603 predefined
__cpp_nontype_template_args 201411 predefined
__cpp_template_template_args 201611 predefined
__cpp_fold_expressions 201603 predefined
__has_include defined predefined
__cpp_lib_byte 201603 <cstddef>
__cpp_lib_hardware_interference_size 201703 <new>
__cpp_lib_launder 201606 <new>
__cpp_lib_uncaught_exceptions 201411 <exception>
__cpp_lib_as_const 201510 <utility>
__cpp_lib_make_from_tuple 201606 <tuple>
__cpp_lib_apply 201603 <tuple>
__has_include(<optional>) 1 predefined
__cpp_lib_optional 201603 <optional>
__has_include(<any>) 1 predefined
__cpp_lib_any 201603 <any>
__has_include(<memory_resource>) 1 predefined
__cpp_lib_memory_resource 201603 <memory_resource>
__cpp_lib_boyer_moore_searcher 201603 <functional>
__has_include(<string_view>) 1 predefined
__cpp_lib_string_view 201603 <string_view>
__cpp_lib_sample 201603 <algorithm>
__cpp_lib_any 201606 <any>
__cpp_lib_optional 201606 <optional>
__cpp_lib_optional 201606 <optional>
__has_include(<variant>) 1 predefined
__cpp_lib_variant 201606 <variant>
__cpp_lib_addressof_constexpr 201603 <memory>
__cpp_lib_raw_memory_algorithms 201606 <memory>
__cpp_lib_transparent_operators 201510 <memory> <functional>
__cpp_lib_enable_shared_from_this 201603 <memory>
__cpp_lib_shared_ptr_weak_type 201606 <memory>
__cpp_lib_shared_ptr_arrays 201611 <memory>
__cpp_lib_invoke 201411 <functional>
__cpp_lib_not_fn 201603 <functional>
__cpp_lib_void_t 201411 <type_traits>
__cpp_lib_bool_constant 201505 <type_traits>
__cpp_lib_type_trait_variable_templates 201510 <type_traits>
__cpp_lib_logical_traits 201510 <type_traits>
__cpp_lib_is_swappable 201603 <type_traits>
__cpp_lib_is_invocable 201703 <type_traits>
__cpp_lib_has_unique_object_representations 201606 <type_traits>
__cpp_lib_is_aggregate 201703 <type_traits>
__cpp_lib_chrono 201611 <chrono>
__has_include(<execution>) 1 predefined
__cpp_lib_execution 201603 <execution>
__cpp_lib_parallel_algorithm 201603 <algorithm> <numeric>
__cpp_lib_to_chars 201611 <utility>
__cpp_lib_string_view 201606 <string> <string_view>
__cpp_lib_allocator_traits_is_always_equal 201411 <memory> <scoped_allocator>
<string> <deque>
<forward_list> <list>
<vector> <map>
<set> <unordered_map>
<unordered_set>
__cpp_lib_incomplete_container_elements 201505 <forwardlist>
<list> <vector>
__cpp_lib_map_try_emplace 201411 <map>
__cpp_lib_unordered_map_try_emplace 201411 <unordered_map>
__cpp_lib_node_extract 201606 <map> <set> <unordered_map> <unordered_set>
__cpp_lib_array_constexpr 201603 <iterator> <array>
__cpp_lib_nonmember_container_access 201411 <iterator> <array> <deque> <forward_list>
<list> <map> <regex> <set> <string>
<unordered_map> <unordered_set> <vector>
__cpp_lib_clamp 201603 <algorithm>
__cpp_lib_gcd_lcm 201606 <numeric>
__cpp_lib_hypot 201603 <cmath>
__cpp_lib_math_special_functions 201603 <cmath>
__has_include(<filesystem>) 1 predefined
__cpp_lib_filesystem 201703 <filesystem>
__cpp_lib_atomic_is_always_lock_free 201603 <atomic>
__cpp_lib_shared_mutex 201505 <shared_mutex>
__cpp_lib_scoped_lock 201703 <mutex>

Feedback question on RTTI and exceptions

With very few exceptions, the features of C++98 have all been implemented in virtually every C++ compiler. But in many compilers, some of them can be enabled/disabled. It is recommended that the macros in the following table should be used to indicate whether one of these features is enabled in the current compilation.

Macro name Value Header
__cpp_rtti 199711 predefined
__cpp_exceptions 199711 predefined

Revision history

Date Document Description
P0941R0 Initial draft
P0941R1 Draft wording, with non-standard content removed and rtti/exception macros made a separate point looking for feedback.