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 named by attribute-token (after macro expansion).
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 |
---|---|---|---|
carries_dependency
|
[[carries_dependency]]
|
200809L | (C++11) |
deprecated
|
[[deprecated]]
|
201309L | (C++14) |
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) |
201907L | (C++20) | ||
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 | Aggregate classes with base classes | 201603L | (C++17) |
__cpp_aggregate_nsdmi | Aggregate classes with default member initializers | 201304L | (C++14) |
__cpp_aggregate_paren_init | Aggregate initialization in the form of direct initialization | 201902L | (C++20) |
__cpp_alias_templates | Alias templates | 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 | 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_concepts | Concepts | 201907L | (C++20) |
__cpp_conditional_explicit | explicit(bool) |
201806L | (C++20) |
__cpp_consteval | Immediate functions | 201811L | (C++20) |
__cpp_constexpr | constexpr | 200704L | (C++11) |
Relaxed constexpr , non-const constexpr methods |
201304L | (C++14) | |
Constexpr lambda | 201603L | (C++17) | |
Trivial default initialization and asm-declaration in constexpr functions | 201907L | (C++20) | |
__cpp_constexpr_dynamic_alloc | Operations for dynamic storage duration in constexpr functions | 201907L | (C++20) |
__cpp_constexpr_in_decltype | Less eager instantiation of constexpr functions | 201711L | (C++20) |
__cpp_constinit | constinit | 201907L | (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) |
CTAD for aggregates and aliases | 201907L | (C++20) | |
__cpp_delegating_constructors | Delegating constructors | 200604L | (C++11) |
__cpp_designated_initializers | Designated initializer | 201707L | (C++20) |
__cpp_enumerator_attributes | Attributes for enumerators | 201411L | (C++17) |
__cpp_fold_expressions | Fold expressions | 201603L | (C++17) |
__cpp_generic_lambdas | Generic lambda expressions | 201304L | (C++14) |
Familiar template syntax for generic lambdas | 201707L | (C++20) | |
__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_coroutine | Coroutines (compiler support) | 201902L | (C++20) |
__cpp_impl_destroying_delete | Destroying operator delete (compiler support) | 201806L | (C++20) |
__cpp_impl_three_way_comparison | Three-way comparison (compiler support) | 201907L | (C++20) |
__cpp_inheriting_constructors | Inheriting constructors | 200802L | (C++11) |
Rewording inheriting constructors | 201511L | (C++17) | |
__cpp_init_captures | Lambda init-capture | 201304L | (C++14) |
Allow pack expansion in lambda init-capture | 201803L | (C++20) | |
__cpp_initializer_lists | List-initialization and std::initializer_list | 200806L | (C++11) |
__cpp_inline_variables | Inline variables | 201606L | (C++17) |
__cpp_lambdas | Lambda expressions | 200907L | (C++11) |
__cpp_modules | Modules | 201907L | (C++20) |
__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) |
Class types and floating-point types in non-type template parameters | 201911L | (C++20) | |
__cpp_nontype_template_parameter_auto | Declaring non-type template parameters with auto |
201606L | (C++17) |
__cpp_nsdmi | Non-static data member initializers | 200809L | (C++11) |
__cpp_range_based_for | Range-based for loop |
200907L | (C++11) |
Range-based for loop with different begin /end types |
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) |
Single-argument 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_using_enum | Using enum | 201907L | (C++20) |
__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 | Constexpr for std::reverse_iterator, std::move_iterator, std::array and range access | 201603L | <iterator> <array> | (C++17) |
ConstexprIterator; constexpr comparison for std::array; misc constexpr bits (std::array::fill et al.) | 201811L | <iterator> <array> | (C++20) | |
__cpp_lib_as_const | std::as_const | 201510L | <utility> | (C++17) |
__cpp_lib_assume_aligned | std::assume_aligned | 201811L | <memory> | (C++20) |
__cpp_lib_atomic_flag_test | std::atomic_flag::test | 201907L | <atomic> | (C++20) |
__cpp_lib_atomic_float | Floating point atomic | 201711L | <atomic> | (C++20) |
__cpp_lib_atomic_is_always_lock_free | constexpr atomic<T>::is_always_lock_free | 201603L | <atomic> | (C++17) |
__cpp_lib_atomic_lock_free_type_aliases | atomic lockfree integral types (std::atomic_signed_lock_free, std::atomic_unsigned_lock_free) | 201907L | <atomic> | (C++20) |
__cpp_lib_atomic_ref | std::atomic_ref | 201806L | <atomic> | (C++20) |
__cpp_lib_atomic_shared_ptr | std::atomic<std::shared_ptr> | 201711L | <memory> | (C++20) |
__cpp_lib_atomic_value_initialization | Fixing atomic initialization (value-initialize std::atomic by default) | 201911L | <atomic> <memory> | (C++20) |
__cpp_lib_atomic_wait | Efficient std::atomic waiting | 201907L | <atomic> | (C++20) |
__cpp_lib_barrier | std::barrier | 201907L | <barrier> | (C++20) |
__cpp_lib_bind_front | std::bind_front | 201907L | <functional> | (C++20) |
__cpp_lib_bit_cast | std::bit_cast | 201806L | <bit> | (C++20) |
__cpp_lib_bitops | Bit operations | 201907L | <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 | std::byte | 201603L | <cstddef> | (C++17) |
__cpp_lib_char8_t | Library support for char8_t | 201907L | <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) |
Constexpr for all the member functions of std::chrono::duration and std::chrono::time_point | 201611L | <chrono> | (C++17) | |
Calendars and Time Zones | 201907L | <chrono> | (C++20) | |
__cpp_lib_chrono_udls | User-defined literals for time types | 201304L | <chrono> | (C++14) |
__cpp_lib_clamp | 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 | 202002L | <concepts> | (C++20) |
__cpp_lib_constexpr_algorithms | Constexpr for algorithms | 201806L | <algorithm> | (C++20) |
__cpp_lib_constexpr_complex | Constexpr for std::complex | 201711L | <complex> | (C++20) |
__cpp_lib_constexpr_dynamic_alloc | Constexpr for std::allocator and related utilities | 201907L | <memory> | (C++20) |
__cpp_lib_constexpr_functional | Misc constexpr bits (std::default_searcher); constexpr INVOKE | 201907L | <functional> | (C++20) |
__cpp_lib_constexpr_iterator | Misc constexpr bits (std::insert_iterator et al.) | 201811L | <iterator> | (C++20) |
__cpp_lib_constexpr_memory | Constexpr in std::pointer_traits | 201811L | <memory> | (C++20) |
__cpp_lib_constexpr_numeric | Constexpr for <numeric> algorithms | 201911L | <numeric> | (C++20) |
__cpp_lib_constexpr_string | Constexpr for std::string | 201907L | <string> | (C++20) |
__cpp_lib_constexpr_string_view | Misc constexpr bits (std::string_view::copy) | 201811L | <string_view> | (C++20) |
__cpp_lib_constexpr_tuple | Misc constexpr bits (std::tuple::operator= et al.) | 201811L | <tuple> | (C++20) |
__cpp_lib_constexpr_utility | Misc constexpr bits (std::pair::operator= et al.) | 201811L | <utility> | (C++20) |
__cpp_lib_constexpr_vector | Constexpr for std::vector | 201907L | <vector> | (C++20) |
__cpp_lib_coroutine | Coroutines (library support) | 201902L | <coroutine> | (C++20) |
__cpp_lib_destroying_delete | Destroying operator delete (library support) |
201806L | <new> | (C++20) |
__cpp_lib_enable_shared_from_this | More precise specification of std::enable_shared_from_this | 201603L | <memory> | (C++17) |
__cpp_lib_endian | std::endian | 201907L | <bit> | (C++20) |
__cpp_lib_erase_if | Uniform container erasure | 202002L | <string> <deque> <forward_list> <list> <vector> <map> <set> <unordered_map> <unordered_set> | (C++20) |
__cpp_lib_exchange_function | std::exchange | 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_format | Text formatting | 201907L | <format> | (C++20) |
__cpp_lib_gcd_lcm | std::gcd, std::lcm | 201606L | <numeric> | (C++17) |
__cpp_lib_generic_associative_lookup | Heterogeneous comparison lookup in associative containers | 201304L | <map> <set> | (C++14) |
__cpp_lib_generic_unordered_lookup | Heterogeneous comparison lookup in unordered associative containers | 201811L | <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_int_pow2 | Integral power-of-2 operations (std::has_single_bit, std::bit_ceil, std::bit_floor, std::bit_length) | 202002L | <bit> | (C++20) |
__cpp_lib_integer_comparison_functions | Integer comparison functions | 202002L | <utility> | (C++20) |
__cpp_lib_integer_sequence | Compile-time integer sequences | 201304L | <utility> | (C++14) |
__cpp_lib_integral_constant_callable | std::integral_constant::operator() | 201304L | <type_traits> | (C++14) |
__cpp_lib_interpolate | std::lerp, std::midpoint | 201902L | <cmath> <numeric> | (C++20) |
__cpp_lib_invoke | std::invoke | 201411L | <functional> | (C++17) |
__cpp_lib_is_aggregate | std::is_aggregate | 201703L | <type_traits> | (C++17) |
__cpp_lib_is_constant_evaluated | 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_layout_compatible | std::is_layout_compatible | 201907L | <type_traits> | (C++20) |
__cpp_lib_is_nothrow_convertible | std::is_nothrow_convertible | 201806L | <type_traits> | (C++20) |
__cpp_lib_is_null_pointer | std::is_null_pointer | 201309L | <type_traits> | (C++14) |
__cpp_lib_is_pointer_interconvertible | Pointer-interconvertibility traits | 201907L | <type_traits> | (C++20) |
__cpp_lib_is_swappable | [nothrow-]swappable traits | 201603L | <type_traits> | (C++17) |
__cpp_lib_jthread | Stop token and joining thread | 201911L | <stop_token> <thread> | (C++20) |
__cpp_lib_latch | std::latch | 201907L | <latch> | (C++20) |
__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() | 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_constants | Mathematical constants | 201907L | <numbers> | (C++20) |
__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 | std::size(), std::data() and std::empty() | 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 | Parallel algorithms | 201603L | <algorithm> <numeric> | (C++17) |
__cpp_lib_polymorphic_allocator | std::polymorphic_allocator<> as a vocabulary type | 201902L | <memory> | (C++20) |
__cpp_lib_quoted_string_io | std::quoted | 201304L | <iomanip> | (C++14) |
__cpp_lib_ranges | Ranges library and constrained algorithms | 201911L | <algorithm> <functional> <iterator> <memory> <ranges> | (C++20) |
__cpp_lib_raw_memory_algorithms | Extending memory management tools | 201606L | <memory> | (C++17) |
__cpp_lib_remove_cvref | std::remove_cvref | 201711L | <type_traits> | (C++20) |
__cpp_lib_result_of_sfinae | std::result_of and SFINAE | 201210L | <type_traits> <functional> | (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 | std::scoped_lock | 201703L | <mutex> | (C++17) |
__cpp_lib_semaphore | std::counting_semaphore , std::binary_semaphore |
201907L | <semaphore> | (C++20) |
__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) |
Array support of std::make_shared | 201707L | <memory> | (C++20) | |
__cpp_lib_shared_ptr_weak_type | shared_ptr::weak_type | 201606L | <memory> | (C++17) |
__cpp_lib_shared_timed_mutex | std::shared_timed_mutex | 201402L | <shared_mutex> | (C++14) |
__cpp_lib_shift | std::shift_left and std::shift_right | 201806L | <algorithm> | (C++20) |
__cpp_lib_smart_ptr_for_overwrite | Smart pointer creation with default initialization (std::allocate_shared_for_overwrite, std::make_shared_for_overwrite, std::make_unique_for_overwrite) | 202002L | <memory> | (C++20) |
__cpp_lib_source_location | Source-code information capture (std::source_location) | 201907L | <source_location> | (C++20) |
__cpp_lib_span | std::span | 202002L | <span> | (C++20) |
__cpp_lib_ssize | std::ssize and unsigned std::span::size | 201902L | <iterator> | (C++20) |
__cpp_lib_starts_ends_with | String prefix and suffix checking (starts_with() and ends_with() for std::string and std::string_view) | 201711L | <string> <string_view> | (C++20) |
__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) |
ConstexprIterator | 201803L | <string> <string_view> | (C++20) | |
__cpp_lib_syncbuf | Synchronized buffered ostream (std::syncbuf, std::osyncstream) and manipulators | 201803L | <syncstream> | (C++20) |
__cpp_lib_three_way_comparison | Three-way comparison (library support); adding three-way comparison to the library | 201907L | <compare> | (C++20) |
__cpp_lib_to_address | Utility to convert a pointer to a raw pointer (std::to_address) | 201711L | <memory> | (C++20) |
__cpp_lib_to_array | std::to_array | 201907L | <array> | (C++20) |
__cpp_lib_to_chars | Elementary string conversions (std::to_chars, std::from_chars) | 201611L | <charconv> | (C++17) |
__cpp_lib_transformation_trait_aliases | Alias templates for TransformationTraits | 201304L | <type_traits> | (C++14) |
__cpp_lib_transparent_operators | Transparent operator functors (std::less<> et al) | 201210L | <functional> | (C++14) |
Transparent std::owner_less (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 | <tuple> <utility> | (C++14) |
__cpp_lib_type_identity | std::type_identity | 201806L | <type_traits> | (C++20) |
__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_unwrap_ref | std::unwrap_ref_decay and std::unwrap_reference | 201811L | <functional> | (C++20) |
__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() { }
Example
Following program dumps C++ compiler features and attributes.
#if __cplusplus < 201100 # error "C++11 or better is required" #endif #include <algorithm> #include <cstring> #include <iomanip> #include <iostream> #include <string> #ifdef __has_include # if __has_include(<version>) # include <version> # endif #endif #define COMPILER_FEATURE_VALUE(value) #value #define COMPILER_FEATURE_ENTRY(name) { #name, COMPILER_FEATURE_VALUE(name) }, #ifdef __has_cpp_attribute # define COMPILER_ATTRIBUTE_VALUE_AS_STRING(s) #s # define COMPILER_ATTRIBUTE_AS_NUMBER(x) COMPILER_ATTRIBUTE_VALUE_AS_STRING(x) # define COMPILER_ATTRIBUTE_ENTRY(attr) \ { #attr, COMPILER_ATTRIBUTE_AS_NUMBER(__has_cpp_attribute(attr)) }, #else # define COMPILER_ATTRIBUTE_ENTRY(attr) { #attr, "_" }, #endif // Change these options to print out only necessary info. static struct PrintOptions { constexpr static bool titles = 1; constexpr static bool attributes = 1; constexpr static bool general_features = 1; constexpr static bool core_features = 1; constexpr static bool lib_features = 1; constexpr static bool supported_features = 1; constexpr static bool unsupported_features = 1; constexpr static bool sorted_by_value = 0; constexpr static bool cxx11 = 1; constexpr static bool cxx14 = 1; constexpr static bool cxx17 = 1; constexpr static bool cxx20 = 1; constexpr static bool cxx23 = 0; } print; struct CompilerFeature { CompilerFeature(const char* name = nullptr, const char* value = nullptr) : name(name), value(value) {} const char* name; const char* value; }; static CompilerFeature cxx[] = { COMPILER_FEATURE_ENTRY(__cplusplus) COMPILER_FEATURE_ENTRY(__cpp_exceptions) COMPILER_FEATURE_ENTRY(__cpp_rtti) #if 0 COMPILER_FEATURE_ENTRY(__GNUC__) COMPILER_FEATURE_ENTRY(__GNUC_MINOR__) COMPILER_FEATURE_ENTRY(__GNUC_PATCHLEVEL__) COMPILER_FEATURE_ENTRY(__GNUG__) COMPILER_FEATURE_ENTRY(__clang__) COMPILER_FEATURE_ENTRY(__clang_major__) COMPILER_FEATURE_ENTRY(__clang_minor__) COMPILER_FEATURE_ENTRY(__clang_patchlevel__) #endif }; static CompilerFeature cxx11[] = { COMPILER_FEATURE_ENTRY(__cpp_alias_templates) COMPILER_FEATURE_ENTRY(__cpp_attributes) COMPILER_FEATURE_ENTRY(__cpp_constexpr) COMPILER_FEATURE_ENTRY(__cpp_decltype) COMPILER_FEATURE_ENTRY(__cpp_delegating_constructors) COMPILER_FEATURE_ENTRY(__cpp_inheriting_constructors) COMPILER_FEATURE_ENTRY(__cpp_initializer_lists) COMPILER_FEATURE_ENTRY(__cpp_lambdas) COMPILER_FEATURE_ENTRY(__cpp_nsdmi) COMPILER_FEATURE_ENTRY(__cpp_range_based_for) COMPILER_FEATURE_ENTRY(__cpp_raw_strings) COMPILER_FEATURE_ENTRY(__cpp_ref_qualifiers) COMPILER_FEATURE_ENTRY(__cpp_rvalue_references) COMPILER_FEATURE_ENTRY(__cpp_static_assert) COMPILER_FEATURE_ENTRY(__cpp_threadsafe_static_init) COMPILER_FEATURE_ENTRY(__cpp_unicode_characters) COMPILER_FEATURE_ENTRY(__cpp_unicode_literals) COMPILER_FEATURE_ENTRY(__cpp_user_defined_literals) COMPILER_FEATURE_ENTRY(__cpp_variadic_templates) }; static CompilerFeature cxx14[] = { COMPILER_FEATURE_ENTRY(__cpp_aggregate_nsdmi) COMPILER_FEATURE_ENTRY(__cpp_binary_literals) COMPILER_FEATURE_ENTRY(__cpp_constexpr) COMPILER_FEATURE_ENTRY(__cpp_decltype_auto) COMPILER_FEATURE_ENTRY(__cpp_generic_lambdas) COMPILER_FEATURE_ENTRY(__cpp_init_captures) COMPILER_FEATURE_ENTRY(__cpp_return_type_deduction) COMPILER_FEATURE_ENTRY(__cpp_sized_deallocation) COMPILER_FEATURE_ENTRY(__cpp_variable_templates) }; static CompilerFeature cxx14lib[] = { COMPILER_FEATURE_ENTRY(__cpp_lib_chrono_udls) COMPILER_FEATURE_ENTRY(__cpp_lib_complex_udls) COMPILER_FEATURE_ENTRY(__cpp_lib_exchange_function) COMPILER_FEATURE_ENTRY(__cpp_lib_generic_associative_lookup) COMPILER_FEATURE_ENTRY(__cpp_lib_integer_sequence) COMPILER_FEATURE_ENTRY(__cpp_lib_integral_constant_callable) COMPILER_FEATURE_ENTRY(__cpp_lib_is_final) COMPILER_FEATURE_ENTRY(__cpp_lib_is_null_pointer) COMPILER_FEATURE_ENTRY(__cpp_lib_make_reverse_iterator) COMPILER_FEATURE_ENTRY(__cpp_lib_make_unique) COMPILER_FEATURE_ENTRY(__cpp_lib_null_iterators) COMPILER_FEATURE_ENTRY(__cpp_lib_quoted_string_io) COMPILER_FEATURE_ENTRY(__cpp_lib_result_of_sfinae) COMPILER_FEATURE_ENTRY(__cpp_lib_robust_nonmodifying_seq_ops) COMPILER_FEATURE_ENTRY(__cpp_lib_shared_timed_mutex) COMPILER_FEATURE_ENTRY(__cpp_lib_string_udls) COMPILER_FEATURE_ENTRY(__cpp_lib_transformation_trait_aliases) COMPILER_FEATURE_ENTRY(__cpp_lib_transparent_operators) COMPILER_FEATURE_ENTRY(__cpp_lib_tuple_element_t) COMPILER_FEATURE_ENTRY(__cpp_lib_tuples_by_type) }; static CompilerFeature cxx17[] = { COMPILER_FEATURE_ENTRY(__cpp_aggregate_bases) COMPILER_FEATURE_ENTRY(__cpp_aligned_new) COMPILER_FEATURE_ENTRY(__cpp_capture_star_this) COMPILER_FEATURE_ENTRY(__cpp_constexpr) COMPILER_FEATURE_ENTRY(__cpp_deduction_guides) COMPILER_FEATURE_ENTRY(__cpp_enumerator_attributes) COMPILER_FEATURE_ENTRY(__cpp_fold_expressions) COMPILER_FEATURE_ENTRY(__cpp_guaranteed_copy_elision) COMPILER_FEATURE_ENTRY(__cpp_hex_float) COMPILER_FEATURE_ENTRY(__cpp_if_constexpr) COMPILER_FEATURE_ENTRY(__cpp_inheriting_constructors) COMPILER_FEATURE_ENTRY(__cpp_inline_variables) COMPILER_FEATURE_ENTRY(__cpp_namespace_attributes) COMPILER_FEATURE_ENTRY(__cpp_noexcept_function_type) COMPILER_FEATURE_ENTRY(__cpp_nontype_template_args) COMPILER_FEATURE_ENTRY(__cpp_nontype_template_parameter_auto) COMPILER_FEATURE_ENTRY(__cpp_range_based_for) COMPILER_FEATURE_ENTRY(__cpp_static_assert) COMPILER_FEATURE_ENTRY(__cpp_structured_bindings) COMPILER_FEATURE_ENTRY(__cpp_template_template_args) COMPILER_FEATURE_ENTRY(__cpp_variadic_using) }; static CompilerFeature cxx17lib[] = { COMPILER_FEATURE_ENTRY(__cpp_lib_addressof_constexpr) COMPILER_FEATURE_ENTRY(__cpp_lib_allocator_traits_is_always_equal) COMPILER_FEATURE_ENTRY(__cpp_lib_any) COMPILER_FEATURE_ENTRY(__cpp_lib_apply) COMPILER_FEATURE_ENTRY(__cpp_lib_array_constexpr) COMPILER_FEATURE_ENTRY(__cpp_lib_as_const) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_is_always_lock_free) COMPILER_FEATURE_ENTRY(__cpp_lib_bool_constant) COMPILER_FEATURE_ENTRY(__cpp_lib_boyer_moore_searcher) COMPILER_FEATURE_ENTRY(__cpp_lib_byte) COMPILER_FEATURE_ENTRY(__cpp_lib_chrono) COMPILER_FEATURE_ENTRY(__cpp_lib_clamp) COMPILER_FEATURE_ENTRY(__cpp_lib_enable_shared_from_this) COMPILER_FEATURE_ENTRY(__cpp_lib_execution) COMPILER_FEATURE_ENTRY(__cpp_lib_filesystem) COMPILER_FEATURE_ENTRY(__cpp_lib_gcd_lcm) COMPILER_FEATURE_ENTRY(__cpp_lib_hardware_interference_size) COMPILER_FEATURE_ENTRY(__cpp_lib_has_unique_object_representations) COMPILER_FEATURE_ENTRY(__cpp_lib_hypot) COMPILER_FEATURE_ENTRY(__cpp_lib_incomplete_container_elements) COMPILER_FEATURE_ENTRY(__cpp_lib_invoke) COMPILER_FEATURE_ENTRY(__cpp_lib_is_aggregate) COMPILER_FEATURE_ENTRY(__cpp_lib_is_invocable) COMPILER_FEATURE_ENTRY(__cpp_lib_is_swappable) COMPILER_FEATURE_ENTRY(__cpp_lib_launder) COMPILER_FEATURE_ENTRY(__cpp_lib_logical_traits) COMPILER_FEATURE_ENTRY(__cpp_lib_make_from_tuple) COMPILER_FEATURE_ENTRY(__cpp_lib_map_try_emplace) COMPILER_FEATURE_ENTRY(__cpp_lib_math_special_functions) COMPILER_FEATURE_ENTRY(__cpp_lib_memory_resource) COMPILER_FEATURE_ENTRY(__cpp_lib_node_extract) COMPILER_FEATURE_ENTRY(__cpp_lib_nonmember_container_access) COMPILER_FEATURE_ENTRY(__cpp_lib_not_fn) COMPILER_FEATURE_ENTRY(__cpp_lib_optional) COMPILER_FEATURE_ENTRY(__cpp_lib_parallel_algorithm) COMPILER_FEATURE_ENTRY(__cpp_lib_raw_memory_algorithms) COMPILER_FEATURE_ENTRY(__cpp_lib_sample) COMPILER_FEATURE_ENTRY(__cpp_lib_scoped_lock) COMPILER_FEATURE_ENTRY(__cpp_lib_shared_mutex) COMPILER_FEATURE_ENTRY(__cpp_lib_shared_ptr_arrays) COMPILER_FEATURE_ENTRY(__cpp_lib_shared_ptr_weak_type) COMPILER_FEATURE_ENTRY(__cpp_lib_string_view) COMPILER_FEATURE_ENTRY(__cpp_lib_to_chars) COMPILER_FEATURE_ENTRY(__cpp_lib_transparent_operators) COMPILER_FEATURE_ENTRY(__cpp_lib_type_trait_variable_templates) COMPILER_FEATURE_ENTRY(__cpp_lib_uncaught_exceptions) COMPILER_FEATURE_ENTRY(__cpp_lib_unordered_map_try_emplace) COMPILER_FEATURE_ENTRY(__cpp_lib_variant) COMPILER_FEATURE_ENTRY(__cpp_lib_void_t) }; static CompilerFeature cxx20[] = { COMPILER_FEATURE_ENTRY(__cpp_aggregate_paren_init) COMPILER_FEATURE_ENTRY(__cpp_char8_t) COMPILER_FEATURE_ENTRY(__cpp_concepts) COMPILER_FEATURE_ENTRY(__cpp_conditional_explicit) COMPILER_FEATURE_ENTRY(__cpp_consteval) COMPILER_FEATURE_ENTRY(__cpp_constexpr) COMPILER_FEATURE_ENTRY(__cpp_constexpr_dynamic_alloc) COMPILER_FEATURE_ENTRY(__cpp_constexpr_in_decltype) COMPILER_FEATURE_ENTRY(__cpp_constinit) COMPILER_FEATURE_ENTRY(__cpp_deduction_guides) COMPILER_FEATURE_ENTRY(__cpp_designated_initializers) COMPILER_FEATURE_ENTRY(__cpp_generic_lambdas) COMPILER_FEATURE_ENTRY(__cpp_impl_coroutine) COMPILER_FEATURE_ENTRY(__cpp_impl_destroying_delete) COMPILER_FEATURE_ENTRY(__cpp_impl_three_way_comparison) COMPILER_FEATURE_ENTRY(__cpp_init_captures) COMPILER_FEATURE_ENTRY(__cpp_modules) COMPILER_FEATURE_ENTRY(__cpp_nontype_template_args) COMPILER_FEATURE_ENTRY(__cpp_using_enum) }; static CompilerFeature cxx20lib[] = { COMPILER_FEATURE_ENTRY(__cpp_lib_array_constexpr) COMPILER_FEATURE_ENTRY(__cpp_lib_assume_aligned) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_flag_test) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_float) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_lock_free_type_aliases) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_ref) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_shared_ptr) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_value_initialization) COMPILER_FEATURE_ENTRY(__cpp_lib_atomic_wait) COMPILER_FEATURE_ENTRY(__cpp_lib_barrier) COMPILER_FEATURE_ENTRY(__cpp_lib_bind_front) COMPILER_FEATURE_ENTRY(__cpp_lib_bit_cast) COMPILER_FEATURE_ENTRY(__cpp_lib_bitops) COMPILER_FEATURE_ENTRY(__cpp_lib_bounded_array_traits) COMPILER_FEATURE_ENTRY(__cpp_lib_char8_t) COMPILER_FEATURE_ENTRY(__cpp_lib_chrono) COMPILER_FEATURE_ENTRY(__cpp_lib_concepts) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_algorithms) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_complex) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_dynamic_alloc) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_functional) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_iterator) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_memory) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_numeric) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_string) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_string_view) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_tuple) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_utility) COMPILER_FEATURE_ENTRY(__cpp_lib_constexpr_vector) COMPILER_FEATURE_ENTRY(__cpp_lib_coroutine) COMPILER_FEATURE_ENTRY(__cpp_lib_destroying_delete) COMPILER_FEATURE_ENTRY(__cpp_lib_endian) COMPILER_FEATURE_ENTRY(__cpp_lib_erase_if) COMPILER_FEATURE_ENTRY(__cpp_lib_execution) COMPILER_FEATURE_ENTRY(__cpp_lib_format) COMPILER_FEATURE_ENTRY(__cpp_lib_generic_unordered_lookup) COMPILER_FEATURE_ENTRY(__cpp_lib_int_pow2) COMPILER_FEATURE_ENTRY(__cpp_lib_integer_comparison_functions) COMPILER_FEATURE_ENTRY(__cpp_lib_interpolate) COMPILER_FEATURE_ENTRY(__cpp_lib_is_constant_evaluated) COMPILER_FEATURE_ENTRY(__cpp_lib_is_layout_compatible) COMPILER_FEATURE_ENTRY(__cpp_lib_is_nothrow_convertible) COMPILER_FEATURE_ENTRY(__cpp_lib_is_pointer_interconvertible) COMPILER_FEATURE_ENTRY(__cpp_lib_jthread) COMPILER_FEATURE_ENTRY(__cpp_lib_latch) COMPILER_FEATURE_ENTRY(__cpp_lib_list_remove_return_type) COMPILER_FEATURE_ENTRY(__cpp_lib_math_constants) COMPILER_FEATURE_ENTRY(__cpp_lib_polymorphic_allocator) COMPILER_FEATURE_ENTRY(__cpp_lib_ranges) COMPILER_FEATURE_ENTRY(__cpp_lib_remove_cvref) COMPILER_FEATURE_ENTRY(__cpp_lib_semaphore) COMPILER_FEATURE_ENTRY(__cpp_lib_shared_ptr_arrays) COMPILER_FEATURE_ENTRY(__cpp_lib_shift) COMPILER_FEATURE_ENTRY(__cpp_lib_smart_ptr_for_overwrite) COMPILER_FEATURE_ENTRY(__cpp_lib_source_location) COMPILER_FEATURE_ENTRY(__cpp_lib_span) COMPILER_FEATURE_ENTRY(__cpp_lib_ssize) COMPILER_FEATURE_ENTRY(__cpp_lib_starts_ends_with) COMPILER_FEATURE_ENTRY(__cpp_lib_string_view) COMPILER_FEATURE_ENTRY(__cpp_lib_syncbuf) COMPILER_FEATURE_ENTRY(__cpp_lib_three_way_comparison) COMPILER_FEATURE_ENTRY(__cpp_lib_to_address) COMPILER_FEATURE_ENTRY(__cpp_lib_to_array) COMPILER_FEATURE_ENTRY(__cpp_lib_type_identity) COMPILER_FEATURE_ENTRY(__cpp_lib_unwrap_ref) }; static CompilerFeature cxx23[] = { COMPILER_FEATURE_ENTRY(__cpp_cxx23_stub) //< Populate eventually }; static CompilerFeature cxx23lib[] = { COMPILER_FEATURE_ENTRY(__cpp_lib_cxx23_stub) //< Populate eventually }; static CompilerFeature attributes[] = { COMPILER_ATTRIBUTE_ENTRY(carries_dependency) COMPILER_ATTRIBUTE_ENTRY(deprecated) COMPILER_ATTRIBUTE_ENTRY(fallthrough) COMPILER_ATTRIBUTE_ENTRY(likely) COMPILER_ATTRIBUTE_ENTRY(maybe_unused) COMPILER_ATTRIBUTE_ENTRY(nodiscard) COMPILER_ATTRIBUTE_ENTRY(noreturn) COMPILER_ATTRIBUTE_ENTRY(no_unique_address) COMPILER_ATTRIBUTE_ENTRY(unlikely) }; constexpr bool is_feature_supported(const CompilerFeature& x) { return x.value[0] != '_' && x.value[0] != '0' ; } inline void print_compiler_feature(const CompilerFeature& x) { constexpr static int max_name_length = 44; //< Update if necessary std::string value{ is_feature_supported(x) ? x.value : "------" }; if (value.back() == 'L') value.pop_back(); //~ 201603L -> 201603 // value.insert(4, 1, '-'); //~ 201603 -> 2016-03 if ( (print.supported_features && is_feature_supported(x)) || (print.unsupported_features && !is_feature_supported(x))) { std::cout << std::left << std::setw(max_name_length) << x.name << " " << value << '\n'; } } template<size_t N> inline void show(char const* title, CompilerFeature (&features)[N]) { if (print.titles) { std::cout << '\n' << std::left << title << '\n'; } if (print.sorted_by_value) { std::sort(std::begin(features), std::end(features), [](CompilerFeature const& lhs, CompilerFeature const& rhs) { return std::strcmp(lhs.value, rhs.value) < 0; }); } for (const CompilerFeature& x : features) { print_compiler_feature(x); } } int main() { if (print.general_features) show("C++ GENERAL", cxx); if (print.cxx11 && print.core_features) show("C++11 CORE", cxx11); if (print.cxx14 && print.core_features) show("C++14 CORE", cxx14); if (print.cxx14 && print.lib_features ) show("C++14 LIB" , cxx14lib); if (print.cxx17 && print.core_features) show("C++17 CORE", cxx17); if (print.cxx17 && print.lib_features ) show("C++17 LIB" , cxx17lib); if (print.cxx20 && print.core_features) show("C++20 CORE", cxx20); if (print.cxx20 && print.lib_features ) show("C++20 LIB" , cxx20lib); if (print.cxx23 && print.core_features) show("C++23 CORE", cxx23); if (print.cxx23 && print.lib_features ) show("C++23 LIB" , cxx23lib); if (print.attributes) show("ATTRIBUTES", attributes); }
Possible output:
C++ GENERAL __cplusplus 202002 __cpp_exceptions 199711 __cpp_rtti 199711 C++11 CORE __cpp_alias_templates 200704 __cpp_attributes 200809 __cpp_constexpr 201907 __cpp_decltype 200707 __cpp_delegating_constructors 200604 __cpp_inheriting_constructors 201511 __cpp_initializer_lists 200806 __cpp_lambdas 200907 __cpp_nsdmi 200809 __cpp_range_based_for 201603 __cpp_raw_strings 200710 __cpp_ref_qualifiers 200710 __cpp_rvalue_references 200610 __cpp_static_assert 201411 __cpp_threadsafe_static_init 200806 __cpp_unicode_characters 200704 __cpp_unicode_literals 200710 __cpp_user_defined_literals 200809 __cpp_variadic_templates 200704 C++14 CORE __cpp_aggregate_nsdmi 201304 __cpp_binary_literals 201304 __cpp_constexpr 201907 __cpp_decltype_auto 201304 __cpp_generic_lambdas 201707 __cpp_init_captures 201803 __cpp_return_type_deduction 201304 __cpp_sized_deallocation ------ __cpp_variable_templates 201304 ... truncated ...