C++20 feature detection macros are a standardized set of preprocessor definitions that allow developers to determine at compile-time whether specific C++20 features are available in their compiler. This pattern was introduced as part of the C++20 standard through ISO/IEC Technical Specification P0941R2. The macros serve as a compiler-agnostic mechanism for feature detection, replacing the traditional approach of checking compiler version numbers or vendor-specific macros. Each feature-test macro is defined only when the corresponding feature is supported by the compiler implementation, with the value typically indicating the year and month of the technical specification that introduced the feature (e.g., 201811L for features approved in November 2018).
Feature detection macros address several critical problems in C++ development. They enable writing portable code that adapts to different compiler capabilities without relying on compiler-specific detection mechanisms. This is particularly valuable for library developers who need to support multiple compiler vendors and versions. The macros also facilitate graceful fallback implementations when modern features aren't available, allowing code to take advantage of new features where possible while maintaining compatibility with older toolchains. Additionally, they provide a clean, standardized way to ensure required features are available before attempting to use them, improving code reliability and reducing obscure compilation errors. The macros are especially useful during the transition period after a new standard is published, when compiler support is uneven across vendors.
Here are some of the most commonly used C++20 feature detection macros:
__cpp_concepts: Checks for language support for concepts__cpp_lib_concepts: Checks for library support for concepts__cpp_coroutines: Checks for language support for coroutines__cpp_lib_coroutine: Checks for library support for coroutines__cpp_lib_ranges: Checks for ranges library support__cpp_lib_format: Checks for std::format support__cpp_lib_span: Checks for std::span support__cpp_modules: Checks for modules support__cpp_impl_three_way_comparison: Checks for language support for three-way comparison__cpp_lib_three_way_comparison: Checks for library support for three-way comparison
#include <version>
#ifdef __cpp_concepts
// Use concepts in your code
template <std::integral T>
T add(T a, T b) { return a + b; }
#else
// Fallback implementation without concepts
template <typename T>
T add(T a, T b) { return a + b; }
#endifFor more complex scenarios, you might check multiple features and adapt accordingly:
#include <version>
// Check for ranges support
#ifdef __cpp_lib_ranges
#include <ranges>
// Use ranges-based implementation
#else
// Use alternative algorithm implementation
#endif
// Check for format support
#ifdef __cpp_lib_format
#include <format>
std::string log_message(const std::string& msg, int code) {
return std::format("[{}] {}", code, msg);
}
#else
#include <sstream>
std::string log_message(const std::string& msg, int code) {
std::ostringstream ss;
ss << "[" << code << "] " << msg;
return ss.str();
}
#endif- Always include the
<version>header before checking feature-test macros - Provide graceful fallbacks for unsupported features
- Use feature-test macros instead of compiler version checks when possible
- Consider using feature-test macros in combination with CMake or other build systems to configure projects based on available features
- Document which features your code requires and which are optional
- Don't confuse language feature macros (like
__cpp_concepts) with library feature macros (like__cpp_lib_concepts) - Be aware that some features might be partially implemented, so testing may still be needed
- Remember that the value of the macro indicates when the feature was standardized, not the quality of the implementation
- Some older compilers might claim support for features via these macros but have buggy implementations
- ISO C++ Standard paper P0941R2: "Feature-test macros and implementation-specific predetermined macros"
- "Professional C++, 5th Edition" by Marc Gregoire (Chapter on Modern C++ Features)
- "C++20: The Complete Guide" by Nicolai M. Josuttis (Section on Feature Testing)
- "The C++ Programming Language, 4th Edition" by Bjarne Stroustrup (Background on C++ evolution)
This code is provided under the MIT License. Feel free to use, modify, and distribute as needed.
Contributions are welcome! Please feel free to submit a Pull Request.