TimelineCpp20CoreLanguage

Feature Testing with C++20

When your program’s compilation broke with a brand-new C++20 feature, you often end with a few questions: Did I do something wrong? Did I find a compiler bug? Does my compiler not yet support this feature? Thanks to the feature testing in C++20, the last question is easy to answer.

TimelineCpp20CoreLanguage

When I experiment with brand-new C++ features, I check which compiler implements the feature I’m interested in. This is when I visit cppreference.com, search for the feature I want to try out, and hope that at least one compiler of the big three (GCC, Clang, MSCV) implements the new feature.

cpp20Support

When I get the answer partially, it is not satisfying. Ultimately, I don’t know who was guilty when the compilation of the brand-new feature failed. There is a more thoughtful way in C++20 to detect if your compiler supports a requested feature.

Feature Testing

The header <version> allows you to ask your compiler for its C++11 or later support. You can ask for attributes, features of the core language, or the library. <version> has about 200 macros defined, which expand to a number when the feature is implemented. The number stands for the year and month the feature was added to the C++ standard. These are the numbers for static_assert, lambdas, and concepts.

 

Rainer D 6 P2 500x500Modernes C++ Mentoring

Be part of my mentoring programs:

  • "Fundamentals for C++ Professionals" (open)
  • "Design Patterns and Architectural Patterns with C++" (open)
  • "C++20: Get the Details" (open)
  • "Concurrency with Modern C++" (starts March 2024)
  • Do you want to stay informed: Subscribe.

     

    __cpp_static_assert  200410L
    __cpp_lambdas  200907L
    __cpp_concepts 201907L
    

    The cppreference.com page to feature testing put all macros together in a long, long source file.

    // featureTest.cpp
    // from cppreference.com
    
    #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);
    }
    

    Of course, the length of the source file is overwhelming. When you want to know more about each macro, visit the page to feature testing. In particular, they provide each macro with a link that can use to get more information about a feature. For example, here is the table on attributes:

    attributes

    To finish my presentation of the <version> header and its macros, I execute the program on the brand-new GCC, Clang, and MSVC compiler. I used Compiler Explorer for the GCC and Clang compilers. On Windows, I had to enable preprocessor macros with the flag /Zc:__cplusplus. Additionally, I compiled on all three platforms with C++20 support.

    For obvious reasons, I only display the support of the C++20 core language.

    • GCC 10.2

    gccCoreCpp20

    • Clang 11.0

    clangCoreCpp20

    • MSVC 19.27

    msvc2CoreCpp20

    The three screenshots speak a clear message about the big three. Their C++20 core language support is quite good at this early stage.

    The type-traits library gets quite an interesting function.

    std::is_constant_evaluated

    The function std::is_constant_evaluated determines whether the function call occurs within a constant-evaluated context or not. Why do we need this function from the type-traits library? In C++20, we have roughly spoken three kinds of functions:

    • consteval declared functions execute at compile-time: consteval int alwaysCompiletime
    • constexpr declared functions can be executed at compile-time or runtime: constexpr int itDepends
    • Usual functions execute at runtime: int alwaysRuntime

    Now, I have to write about the complicated case: constexpr. A constexpr function call occurs within a constant-evaluated context or not. Sometimes these functions should behave differently whether the function call occurs within a constant-evaluated context or not. A constexpr function such as getSum has the potential to run at compile-time.

    constexpr int getSum(int l, int r) {
        return l + r;
    }
    

    How can be sure that the function call occurs within a constant-evaluated context or not?

    • A constant-evaluated context
      • implicit: Call in a constant expression
      • explicit: Request the result using constexpr
    • A non-constant-evaluated context
      • Function arguments are not constant expressions

    cppreference.com shows a smart use case. At compile-time, you calculate the power of two numbers manually; at runtime, you use std::pow.

    // constantEvaluated.cpp
    
    #include <type_traits>
    #include <cmath>
    #include <iostream>
     
    constexpr double power(double b, int x) {
        if (std::is_constant_evaluated() && !(b == 0.0 && x < 0)) {
            
            if (x == 0)
                return 1.0;
            double r = 1.0, p = x > 0 ? b : 1.0 / b;
            auto u = unsigned(x > 0 ? x : -x);
            while (u != 0) {
                if (u & 1) r *= p;
                u /= 2;
                p *= p;
            }
            return r;
        } 
        else {
            return std::pow(b, double(x));
        }
    }
     
    int main() {
        
        std::cout << std::endl;
        
        constexpr double kilo1 = power(10.0, 3);
        std::cout << "kilo1: " << kilo1 << std::endl;
        
        int n = 3;
        double kilo2 = power(10.0, n);
        std::cout << "kilo2: " << kilo2 << std::endl;
        
        std::cout << std::endl;
        
    }
    

    There is one interesting observation I want to share. It is possible to use std::is_constant_evaluated in an as consteval declared function or in a function that can only run at runtime. Of course, the result of these calls is always true or false.

    What’s next?

    I’m nearly done with my presentation on the C++20 library. Only two features are still missing bevor I dive into concurrency in C++20: the bit manipulation library and std::source_location.

    Thanks a lot to my Patreon Supporters: Matt Braun, Roman Postanciuc, Tobias Zindl, G Prvulovic, Reinhold Dröge, Abernitzke, Frank Grimm, Sakib, Broeserl, António Pina, Sergey Agafyin, Андрей Бурмистров, Jake, GS, Lawton Shoemake, Jozo Leko, John Breland, Venkat Nandam, Jose Francisco, Douglas Tinkham, Kuchlong Kuchlong, Robert Blanch, Truels Wissneth, Kris Kafka, Mario Luoni, Friedrich Huber, lennonli, Pramod Tikare Muralidhara, Peter Ware, Daniel Hufschläger, Alessandro Pezzato, Bob Perry, Satish Vangipuram, Andi Ireland, Richard Ohnemus, Michael Dunsky, Leo Goodstadt, John Wiederhirn, Yacob Cohen-Arazi, Florian Tischler, Robin Furness, Michael Young, Holger Detering, Bernd Mühlhaus, Stephen Kelley, Kyle Dean, Tusar Palauri, Dmitry Farberov, Juan Dent, George Liao, Daniel Ceperley, Jon T Hess, Stephen Totten, Wolfgang Fütterer, Matthias Grün, Phillip Diekmann, Ben Atakora, Ann Shatoff, Rob North, Bhavith C Achar, Marco Parri Empoli, moon, Philipp Lenk, Hobsbawm, and Charles-Jianye Chen.

    Thanks, in particular, to Jon Hess, Lakshman, Christian Wittenhorst, Sherhy Pyton, Dendi Suhubdy, Sudhakar Belagurusamy, Richard Sargeant, Rusty Fleming, John Nebel, Mipko, Alicja Kaminska, Slavko Radman, and David Poole.

    My special thanks to Embarcadero
    My special thanks to PVS-Studio
    My special thanks to Tipi.build 
    My special thanks to Take Up Code
    My special thanks to SHAVEDYAKS

    Seminars

    I’m happy to give online seminars or face-to-face seminars worldwide. Please call me if you have any questions.

    Standard Seminars (English/German)

    Here is a compilation of my standard seminars. These seminars are only meant to give you a first orientation.

    • C++ – The Core Language
    • C++ – The Standard Library
    • C++ – Compact
    • C++11 and C++14
    • Concurrency with Modern C++
    • Design Pattern and Architectural Pattern with C++
    • Embedded Programming with Modern C++
    • Generic Programming (Templates) with C++
    • Clean Code with Modern C++
    • C++20

    Online Seminars (German)

    Contact Me

    Modernes C++ Mentoring,

     

     

    0 replies

    Leave a Reply

    Want to join the discussion?
    Feel free to contribute!

    Leave a Reply

    Your email address will not be published. Required fields are marked *