Feature testing (C++20)
The standard defines a set of preprocessor macros corresponding to C++ language and library features introduced in C++11 or later. They are intended as a simple and portable way to detect the presence of said features.
Attributes
__has_cpp_attribute( attribute-token )
|
|||||||||
Checks for the presence of an attribute.
For standard attributes, it will expand to the year and month in which the attribute was added to the working draft (see table below), the presence of vendor-specific attributes is determined by a non-zero value.
__has_cpp_attribute
can be expanded in the expression of #if and #elif.
It is treated as a defined macro by #ifdef, #ifndef and defined but cannot be used anywhere else.
attribute-token | Attribute | Value | Standard |
---|---|---|---|
assert
|
[[assert]]
|
201806L | (C++20) |
carries_dependency
|
[[carries_dependency]]
|
200809L | (C++11) |
deprecated
|
[[deprecated]]
|
201309L | (C++14) |
ensures
|
[[ensures]]
|
201806L | (C++20) |
expects
|
[[expects]]
|
201806L | (C++20) |
fallthrough
|
[[fallthrough]]
|
201603L | (C++17) |
likely
|
[[likely]]
|
201803L | (C++20) |
maybe_unused
|
[[maybe_unused]]
|
201603L | (C++17) |
no_unique_address
|
[[no_unique_address]]
|
201803L | (C++20) |
nodiscard
|
[[nodiscard]]
|
201603L | (C++17) |
noreturn
|
[[noreturn]]
|
200809L | (C++11) |
unlikely
|
[[unlikely]]
|
201803L | (C++20) |
Language features
The following macros are predefined in every translation unit. Each macro expands to an integer literal corresponding to the year and month when the corresponding feature has been included in the working draft.
When a feature changes significantly, the macro will be updated accordingly.
Macro name | Feature | Value | Std |
---|---|---|---|
__cpp_aggregate_bases | Extension to aggregate initialization | 201603L | (C++17) |
__cpp_aggregate_nsdmi | Member initializers and aggregates | 201304L | (C++14) |
__cpp_aggregate_paren_init | Aggregate initialization in the form of direct initialization | 201902L | (C++20) |
__cpp_alias_templates | Template aliases | 200704L | (C++11) |
__cpp_aligned_new | Dynamic memory allocation for over-aligned data | 201606L | (C++17) |
__cpp_attributes | Attributes | 200809L | (C++11) |
__cpp_binary_literals | Binary literals in the C++ core language | 201304L | (C++14) |
__cpp_capture_star_this | Lambda capture of *this by value as [=,*this] | 201603L | (C++17) |
__cpp_char8_t | char8_t |
201811L | (C++20) |
__cpp_conditional_explicit | explicit(bool) |
201806L | (C++20) |
__cpp_constexpr | constexpr | 200704L | (C++11) |
Relaxing constraints on constexpr functions / constexpr member functions and implicit const |
201304L | (C++14) | |
Constexpr lambda | 201603L | (C++17) | |
__cpp_coroutines | Coroutines | 201902L | (C++20) |
__cpp_decltype | decltype | 200707L | (C++11) |
__cpp_decltype_auto | Return type deduction for normal functions | 201304L | (C++14) |
__cpp_deduction_guides | Template argument deduction for class templates | 201703L | (C++17) |
__cpp_delegating_constructors | Delegating constructors | 200604L | (C++11) |
__cpp_enumerator_attributes | Attributes for enumerators | 201411L | (C++17) |
__cpp_fold_expressions | Fold expressions | 201603L | (C++17) |
__cpp_generic_lambdas | Generic (polymorphic) lambda expressions | 201304L | (C++14) |
__cpp_guaranteed_copy_elision | Guaranteed copy elision through simplified value categories | 201606L | (C++17) |
__cpp_hex_float | Hexadecimal floating literals | 201603L | (C++17) |
__cpp_if_constexpr | constexpr if |
201606L | (C++17) |
__cpp_impl_destroying_delete | Destroying operator delete (compiler support) | 201806L | (C++20) |
__cpp_impl_three_way_comparison | Three-way comparison (compiler support) | 201711L | (C++20) |
__cpp_inheriting_constructors | Inheriting constructors | 200802L | (C++11) |
Rewording inheriting constructors | 201511L | (C++17) | |
__cpp_init_captures | Generalized lambda-capture | 201304L | (C++14) |
__cpp_initializer_lists | Initializer lists | 200806L | (C++11) |
__cpp_inline_variables | Inline variables | 201606L | (C++17) |
__cpp_lambdas | Lambda expressions | 200907L | (C++11) |
__cpp_namespace_attributes | Attributes for namespaces | 201411L | (C++17) |
__cpp_noexcept_function_type | Make exception specifications be part of the type system | 201510L | (C++17) |
__cpp_nontype_template_args | Allow constant evaluation for all non-type template arguments | 201411L | (C++17) |
__cpp_nontype_template_parameter_auto | Declaring non-type template parameters with auto |
201606L | (C++17) |
__cpp_nontype_template_parameter_class | Class types in non-type template parameters | 201806L | (C++20) |
__cpp_nsdmi | Non-static data member initializers | 200809L | (C++11) |
__cpp_range_based_for | Range-based for loop |
200907L | (C++11) |
Generalized range-based for loop |
201603L | (C++17) | |
__cpp_raw_strings | Raw string literals | 200710L | (C++11) |
__cpp_ref_qualifiers | ref-qualifiers | 200710L | (C++11) |
__cpp_return_type_deduction | Return type deduction for normal functions | 201304L | (C++14) |
__cpp_rvalue_references | Rvalue reference | 200610L | (C++11) |
__cpp_sized_deallocation | Sized deallocation | 201309L | (C++14) |
__cpp_static_assert | static_assert | 200410L | (C++11) |
Extended static_assert |
201411L | (C++17) | |
__cpp_structured_bindings | structured bindings | 201606L | (C++17) |
__cpp_template_template_args | Matching of template template-arguments | 201611L | (C++17) |
__cpp_threadsafe_static_init | Dynamic initialization and destruction with concurrency | 200806L | (C++11) |
__cpp_unicode_characters | New character types (char16_t and char32_t) | 200704L | (C++11) |
__cpp_unicode_literals | Unicode string literals | 200710L | (C++11) |
__cpp_user_defined_literals | User-defined literals | 200809L | (C++11) |
__cpp_variable_templates | Variable templates | 201304L | (C++14) |
__cpp_variadic_templates | Variadic templates | 200704L | (C++11) |
__cpp_variadic_using | Pack expansions in using -declarations |
201611L | (C++17) |
Library features
The following macros are defined if the header <version> or any of the corresponding headers in the table below is included. Each macro expands to an integer literal corresponding to the year and month when the corresponding feature has been included in the working draft.
When a feature changes significantly, the macro will be updated accordingly.
Macro name | Feature | Value | Header | Std |
---|---|---|---|---|
__cpp_lib_addressof_constexpr | constexpr std::addressof | 201603L | <memory> | (C++17) |
__cpp_lib_allocator_traits_is_always_equal | std::allocator_traits::is_always_equal | 201411L | <memory> <scoped_allocator> <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set> | (C++17) |
__cpp_lib_any | std::any | 201606L | <any> | (C++17) |
__cpp_lib_apply | std::apply | 201603L | <tuple> | (C++17) |
__cpp_lib_array_constexpr | Adding constexpr modifiers to std::reverse_iterator, std::move_iterator, std::array and range access | 201603L | <iterator> <array> | (C++17) |
__cpp_lib_as_const | std::as_const | 201510L | <utility> | (C++17) |
__cpp_lib_atomic_is_always_lock_free | constexpr atomic<T>::is_always_lock_free | 201603L | <atomic> | (C++17) |
__cpp_lib_atomic_ref | std::atomic_ref | 201806L | <atomic> | (C++20) |
__cpp_lib_bind_front | std::bind_front | 201811L | <functional> | (C++20) |
__cpp_lib_bit_cast | std::bit_cast | 201806L | <bit> | (C++20) |
__cpp_lib_bool_constant | std::bool_constant | 201505L | <type_traits> | (C++17) |
__cpp_lib_bounded_array_traits | std::is_bounded_array, std::is_unbounded_array | 201902L | <type_traits> | (C++20) |
__cpp_lib_boyer_moore_searcher | Searchers | 201603L | <functional> | (C++17) |
__cpp_lib_byte | A byte type definition | 201603L | <cstddef> | (C++17) |
__cpp_lib_char8_t | library support for char8_t | 201811L | <atomic> <filesystem> <istream> <limits> <locale> <ostream> <string> <string_view> | (C++20) |
__cpp_lib_chrono | rounding functions for std::chrono::duration and std::chrono::time_point | 201510L | <chrono> | (C++17) |
making all the member functions of std::chrono::duration and std::chrono::time_point constexpr | 201611L | <chrono> | (C++17) | |
__cpp_lib_chrono_udls | User-defined literals for time types | 201304L | <chrono> | (C++14) |
__cpp_lib_clamp | An algorithm to "clamp" a value between a pair of boundary values (std::clamp) | 201603L | <algorithm> | (C++17) |
__cpp_lib_complex_udls | User-defined Literals for std::complex | 201309L | <complex> | (C++14) |
__cpp_lib_concepts | Standard library concepts | 201806L | <concepts> | (C++20) |
__cpp_lib_constexpr_misc | Constexpr for miscellaneous facilities | 201811L | <array> <functional> <iterator> <string_view> <tuple> <utility> | (C++20) |
__cpp_lib_constexpr_swap_algorithms | Constexpr for swap and swap related functions | 201806L | <algorithm> | (C++20) |
__cpp_lib_destroying_delete | Destroying operator delete (library support) | 201806L | <new> | (C++20) |
__cpp_lib_enable_shared_from_this | Re-enabling shared_from_this | 201603L | <memory> | (C++17) |
__cpp_lib_erase_if | Uniform container erasure | 201811L | <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set> | (C++20) |
__cpp_lib_exchange_function | exchange() utility function | 201304L | <utility> | (C++14) |
__cpp_lib_execution | Execution policies | 201603L | <execution> | (C++17) |
std::execution::unsequenced_policy | 201902L | <execution> | (C++20) | |
__cpp_lib_filesystem | Filesystem library | 201703L | <filesystem> | (C++17) |
__cpp_lib_gcd_lcm | std::gcd, std::lcm | 201606L | <numeric> | (C++17) |
__cpp_lib_generic_associative_lookup | Adding heterogeneous comparison lookup to associative containers | 201304L | <map> <set> | (C++14) |
__cpp_lib_generic_unordered_lookup | Adding heterogeneous comparison lookup to unordered associative containers | 201811L | <unordered_map> <unordered_set> | (C++20) |
__cpp_lib_generic_unordered_hash_lookup | Adding pre-calculated hash value lookup to unordered associative containers | 201902L | <unordered_map> <unordered_set> | (C++20) |
__cpp_lib_hardware_interference_size | constexpr std::hardware_{constructive, destructive}_interference_size | 201703L | <new> | (C++17) |
__cpp_lib_has_unique_object_representations | std::has_unique_object_representations | 201606L | <type_traits> | (C++17) |
__cpp_lib_hypot | 3-argument overload of std::hypot | 201603L | <cmath> | (C++17) |
__cpp_lib_incomplete_container_elements | Minimal incomplete type support for standard containers | 201505L | <forward_list> <list> <vector> | (C++17) |
__cpp_lib_integer_sequence | Compile-time integer sequences | 201304L | <utility> | (C++14) |
__cpp_lib_interpolate | std::lerp(), std::midpoint() | 201902L | <cmath> <numeric> | (C++20) |
__cpp_lib_integral_constant_callable | std::integral_constant::operator() | 201304L | <type_traits> | (C++14) |
__cpp_lib_invoke | std::invoke function template | 201411L | <functional> | (C++17) |
__cpp_lib_is_aggregate | std::is_aggregate type trait | 201703L | <type_traits> | (C++17) |
__cpp_lib_is_constant_evaluated | Constant-evaluated context detection (std::is_constant_evaluated()) | 201811L | <type_traits> | (C++20) |
__cpp_lib_is_final | std::is_final | 201402L | <type_traits> | (C++14) |
__cpp_lib_is_invocable | std::is_invocable, std::invoke_result | 201703L | <type_traits> | (C++17) |
__cpp_lib_is_null_pointer | std::is_null_pointer | 201309L | <type_traits> | (C++14) |
__cpp_lib_is_swappable | [nothrow-]swappable traits | 201603L | <type_traits> | (C++17) |
__cpp_lib_launder | Core Issue 1776: Replacement of class objects containing reference members (std::launder) | 201606L | <new> | (C++17) |
__cpp_lib_list_remove_return_type | Change the return type of the remove(), remove_if() and unique() members of std::forward_list and std::list | 201806L | <forward_list> <list> | (C++20) |
__cpp_lib_logical_traits | Logical operator type traits | 201510L | <type_traits> | (C++17) |
__cpp_lib_make_from_tuple | std::make_from_tuple: apply for construction | 201606L | <tuple> | (C++17) |
__cpp_lib_make_reverse_iterator | std::make_reverse_iterator | 201402L | <iterator> | (C++14) |
__cpp_lib_make_unique | std::make_unique | 201304L | <memory> | (C++14) |
__cpp_lib_map_try_emplace | std::map::try_emplace, std::map::insert_or_assign | 201411L | <map> | (C++17) |
__cpp_lib_math_special_functions | Mathematical special functions for C++17 | 201603L | <cmath> | (C++17) |
__cpp_lib_memory_resource | std::pmr::memory_resource | 201603L | <memory_resource> | (C++17) |
__cpp_lib_node_extract | Splicing maps and sets (std::map::extract, std::map::merge, std::map::insert(node_type), etc) | 201606L | <map> <set> <unordered_map> <unordered_set> | (C++17) |
__cpp_lib_nonmember_container_access | Non-member size() and more (uniform container access) |
201411L | <iterator> <array> <deque> <forward_list> <list> <map> <regex> <set> <string> <unordered_map> <unordered_set> <vector> | (C++17) |
__cpp_lib_not_fn | std::not_fn | 201603L | <functional> | (C++17) |
__cpp_lib_null_iterators | Null LegacyForwardIterators | 201304L | <iterator> | (C++14) |
__cpp_lib_optional | std::optional | 201606L | <optional> | (C++17) |
__cpp_lib_parallel_algorithm | Adopt the Parallelism TS for C++17 | 201603L | <algorithm> <numeric> | (C++17) |
__cpp_lib_quoted_string_io | std::quoted | 201304L | <iomanip> | (C++14) |
__cpp_lib_ranges | Ranges library and constrained algorithms | 201811L | <algorithm> <functional> <iterator> <memory> <ranges> | (C++20) |
__cpp_lib_raw_memory_algorithms | Extending memory management tools | 201606L | <memory> | (C++17) |
__cpp_lib_result_of_sfinae | std::result_of and SFINAE | 201210L | <functional> <type_traits> | (C++14) |
__cpp_lib_robust_nonmodifying_seq_ops | Making non-modifying sequence operations more robust (two-range overloads for std::mismatch, std::equal and std::is_permutation) | 201304L | <algorithm> | (C++14) |
__cpp_lib_sample | std::sample | 201603L | <algorithm> | (C++17) |
__cpp_lib_scoped_lock | Variadic std::lock_guard (std::scoped_lock) | 201703L | <mutex> | (C++17) |
__cpp_lib_shared_mutex | std::shared_mutex (untimed) | 201505L | <shared_mutex> | (C++17) |
__cpp_lib_shared_ptr_arrays | std::shared_ptr<T[]> | 201611L | <memory> | (C++17) |
__cpp_lib_shared_ptr_weak_type | shared_ptr::weak_type | 201606L | <memory> | (C++17) |
__cpp_lib_shared_timed_mutex | Rename shared_mutex to shared_timed_mutex |
201402L | <shared_mutex> | (C++14) |
__cpp_lib_string_udls | User-defined literals for string types | 201304L | <string> | (C++14) |
__cpp_lib_string_view | std::string_view | 201606L | <string> <string_view> | (C++17) |
__cpp_lib_three_way_comparison | Three-way comparison (library support) | 201711L | <compare> | (C++20) |
__cpp_lib_to_chars | Elementary string conversions (std::to_chars, std::from_chars) | 201611L | <charconv> | (C++17) |
__cpp_lib_transformation_trait_aliases | TransformationTraits Redux | 201304L | <type_traits> | (C++14) |
__cpp_lib_transparent_operators | Transparent operator functors (std::less<> et al) | 201210L | <functional> | (C++14) |
Making std::owner_less more flexible (std::owner_less<void>) | 201510L | <memory> <functional> | (C++17) | |
__cpp_lib_tuple_element_t | std::tuple_element_t | 201402L | <tuple> | (C++14) |
__cpp_lib_tuples_by_type | Addressing tuples by type | 201304L | <utility> <tuple> | (C++14) |
__cpp_lib_type_trait_variable_templates | Type traits variable templates (std::is_void_v, etc) | 201510L | <type_traits> | (C++17) |
__cpp_lib_uncaught_exceptions | std::uncaught_exceptions | 201411L | <exception> | (C++17) |
__cpp_lib_unordered_map_try_emplace | std::unordered_map::try_emplace, std::unordered_map::insert_or_assign | 201411L | <unordered_map> | (C++17) |
__cpp_lib_variant | std::variant: a type-safe union for C++17 | 201606L | <variant> | (C++17) |
__cpp_lib_void_t | std::void_t | 201411L | <type_traits> | (C++17) |
Example
#ifdef __has_include // Check if __has_include is present # if __has_include(<optional>) // Check for a standard library # include <optional> # elif __has_include(<experimental/optional>) // Check for an experimental version # include <experimental/optional> # elif __has_include(<boost/optional.hpp>) // Try with an external library # include <boost/optional.hpp> # else // Not found at all # error "Missing <optional>" # endif #endif #ifdef __has_cpp_attribute // Check if __has_cpp_attribute is present # if __has_cpp_attribute(deprecated) // Check for an attribute # define DEPRECATED(msg) [[deprecated(msg)]] # endif #endif #ifndef DEPRECATED # define DEPRECATED(msg) #endif DEPRECATED("foo() has been deprecated") void foo(); #if __cpp_constexpr >= 201304 // Check for a specific version of a feature # define CONSTEXPR constexpr #else # define CONSTEXPR inline #endif CONSTEXPR int bar(unsigned i) { #if __cpp_binary_literals // Check for the presence of a feature unsigned mask1 = 0b11000000; unsigned mask2 = 0b00000111; #else unsigned mask1 = 0xC0; unsigned mask2 = 0x07; #endif if ( i & mask1 ) return 1; if ( i & mask2 ) return 2; return 0; } int main() { }
See Also
Standing Document 6 | The official document on Feature Test Recommendations |