Home DEVELOPER C++20: Detecting compiler functions with feature testing macros

C++20: Detecting compiler functions with feature testing macros

0


C++20 comes with feature testing macros that check the compiler to see which features it supports.

Advertisement




Anyone who tries the latest C++ features often receives error messages. Now the question arises, who is responsible for this?

  1. Have you made any mistakes yourself?
  2. Does the used compiler support this feature?
  3. Is there a compiler bug that occurred?




Rainer Grimm has been working as a software architect, team and training manager for many years. He enjoys writing articles on the programming languages ​​C++, Python and Haskell, but also frequently speaking at specialist conferences. On his blog Modern C++ he discusses his passion C++ in depth.

Option 3 is a rare occurrence, so you only need to answer one question: does the compiler support this feature?

This question is easy to answer because of cppreference and feature testing macros.

As is often the case cppreference.com/compiler_support Answers to questions about the key language and libraries, including the C++11 standards up to C++26.

The following tables provide an overview of the main language and library support for the C++26 standard.



If the answers are not specific enough, the feature testing macros in C++20 will help.

With header You can ask the compiler about its support for C++11 or higher. One can ask about the features, characteristics of the core language or library. has defined over 300 macros that expand to a number when the feature is implemented. The number indicates the year and month in which the feature was added to the C++ draft standards. These are the numbers for static_assert, Lambdas And Concepts,

__cpp_static_assert  200410L
__cpp_lambdas  200907L
__cpp_concepts 201907L

Page Feature Testing Macros Lists all macros.

The following program, which I adapted and adapted from cppreference, demonstrates all the macros in the core C++20 language. flag /Zc:__cplusplus Activates the feature test macro on Windows.

// featureTesting20.cpp
// from cppreference.com

#if __cplusplus < 201100
#  error "C++11 or better is required"
#endif
 
#include 
#include 
#include 
#include 
#include 
 
#ifdef __has_include
# if __has_include()
#   include 
# 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
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 of Compiler Explorer show the C++20 support of the GCC 8.1, 10.1, and 14.1 compilers.







In my next article I will continue my journey through C++23.


(RME)

Product workers: AI as a wingman for product owners

NO COMMENTS

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Exit mobile version