Feature Testing Macros
The feature testing macros is a relatively unknown feature in C + + 20. They give you the definitive answer to which C++ feature your compiler supports.
When you try out the latest C++ features, you often get errors. Now the question is: who is to blame?
- Did you make a mistake?
- Does your compiler support this feature?
- Did you find a compiler bug?
Option 3 occurs rarely, so you have only one question to answer: Does your compiler support this feature?
This question is easy to answer thanks to the cppreference and the feature testing macros.
C++ Compiler Support
As so often, cppreference.com/compiler_support answers questions about the core language and library, including the C++11 standards up to C++ 26.
The following tables give you an overview of the core language and library support for the C++26 standard.
C++26 Core Language
C++26 Library
Are the answers not specific enough? Let me jump to the feature testing macros in C++20.
Feature Testing macros
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 more than 300 macros defined, which expand to a number when the feature is implemented. The number represents the year and month the feature was added to the C++ draft standard. These are the numbers for static_assert, lambdas, and concepts
.
The page feature testing macros shows all macros.
Modernes C++ Mentoring
Do you want to stay informed: Subscribe.
The following program, adopted from the cppreference, displays all C++20 core language macros. The flag /Zc:__cplusplus
enables the feature testing macro on Windows.
// featureTesting20.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 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) }; 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.cxx20 && print.core_features) show("C++20 CORE", cxx20); }
The following screenshots from the Compiler Explorer show the C++20 support of GCC 8.1, 10.1, and 14.1 compilers.
- GCC 8.1
- GCC 10.1
- GCC 14.1
What’s next?
With my next post, I continue my journey through C + + 23.
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, 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, 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, Philipp Lenk, Charles-Jianye Chen, Keith Jeffery, Matt Godbolt, and Honey Sukesan.
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 |
Modernes C++ GmbH
Modernes C++ Mentoring (English)
Rainer Grimm
Yalovastraße 20
72108 Rottenburg
Mail: schulung@ModernesCpp.de
Mentoring: www.ModernesCpp.org
Modernes C++ Mentoring,