Feature detection. More...
#include <UGMISC_PREDEFS_HEADER>#include <version>Go to the source code of this file.
Classes | |
| struct | ugmisc::Features |
Macros | |
| #define | UGMISC_PREDEFS_HEADER "quoted_header_name" |
| #define | UGMISC_HAVE_VERSION |
| #define | UGMISC_HAS_INCLUDE_OR_IGNORE(...) |
| #define | UGMISC_HAVE_CONSTEXPR_DESTRUCTORS |
| #define | UGMISC_NO_CONSTEXPR_DESTRUCTORS |
| #define | UGMISC_HAVE_CONSTEVAL |
| #define | UGMISC_HAVE_CONSTEVAL_IF |
| Defined if consteval if is supported. | |
| #define | UGMISC_HAVE_BIT_CAST |
| #define | UGMISC_HAVE_BITOPS |
| #define | UGMISC_HAVE_CONSTEXPR_SWAP_ALGORITHMS |
Feature detection.
Feature detection is mostly just standard feature detection, but there are some things we would find ourselves doing again to make it work if it wasn't all in one place, so here it is. Plus this way features, in addition to being macros, are also static constexpr members of a Features class, use of which is sometimes more convenient than a preprocessor directive.
We don't try to be fancy here. C++17 and later are supported. It is assumed that all C++17 language and library features work. Everything else depends on feature test macros provided by compiler and the version header.
You can still include <version> if __has_include doesn't work, by predefining UGMISC_HAVE_VERSION.
Some of the features don't have proper feature test macros. For these we guess based on the C++ standard version number.
But it is possible to predefine a macro for each of those features. This allows a build system to run a feature test during setup. Either define all of the required macros on the compiler command line, or define them in a header and define UGMISC_PREDEFS_HEADER to cause them to be included.
Or of course you could not define UGMISC_PREDEFS_HEADER and always include the predefs header yourself before including ugmisc/features.hpp.
Don't forget the double quotes or angle brackets!
The following macros are respected by features.hpp if they are predefined.
Some of the features are not so much detected as guessed. These features may be detected by a build system at build configuration time. For example, using Meson, we can create a configuration_data object to store our test results:
config = configuration_data()
cpp = meson.get_compiler('cpp')
Then just in case the __has_include macro doesn't work for some reason:
if cpp.has_header('version')
config.set('UGMISC_HAVE_VERSION', true)
endif
This will tell features.hpp that including <version> will work.
Defining one of the following two macros tells ugmisc/features.hpp not to try to guess constexpr desctuctors support. If it does guess it will guess purely based on whether __cplusplus tells it the standard in use is C++20 or later.
if cpp.compiles('struct X { constexpr ~X() {} };')
config.set('UGMISC_HAVE_CONSTEXPR_DESTRUCTORS', true)
else
config.set('UGMISC_NO_CONSTEXPR_DESTRUCTORS', true)
endif
Now we either have to set all our macros on the command line, or set the UGMISC_PREDEFS_HEADER macro on the command line and generate a header containing the other macro definitions. In this example we do the latter.
config_file = configure_file( configuration: config, output: 'config.hpp', output_format: 'c' ) config_include = config_file.full_path()
The header name needs to be quoted, and to do that safely we will set it using a configuration object's set_quoted method.
In the unit tests' meson.build script there is an example of using the fs module to turn the config header path into a short relative path. This also means we know the path has no weird characters so we can quote it by simply adding the quote chaaracters, instead of using set_quoted as we do here.
tmpconf = configuration_data()
tmpconf.set_quoted('hdr', test_conf_include)
quoted_header = tmpconf.get('hdr')
add_project_arguments(
f'-DUGMISC_PREDEFS_HEADER=@quoted_header@',
language: 'cpp'
)
This is similar to how it is done when building the unit tests, if the user sets the 'test-build-uses-setup-feature-tests' option.
| #define UGMISC_HAVE_BIT_CAST |
Defined if std::bit_cast is supported.
| #define UGMISC_HAVE_BITOPS |
Defined if <bit> is supported.
| #define UGMISC_HAVE_CONSTEVAL |
Defined if consteval keyword supported.
| #define UGMISC_HAVE_CONSTEVAL_IF |
Defined if consteval if is supported.
| #define UGMISC_HAVE_CONSTEXPR_DESTRUCTORS |
Defined if constexpr desctuctors are supported. Detection is based on the C++ standard version number only, unless
If UGMISC_HAVE_CONSTEXPR_DESTRUCTORS or UGMISC_NO_CONSTEXPR_DESTRUCTORS is predefined, that will override features.hpp's detection of this feature. A build script may define one of these macros in response to a compiler test.
| #define UGMISC_HAVE_CONSTEXPR_SWAP_ALGORITHMS |
Defined if std::swap, std::exchange etc are constexpr.
| #define UGMISC_HAVE_VERSION |
This macro is not defined by features.hpp. If it is predefined before including features.hpp, or it is defined in the header identified by UGMISC_PREDEFS_HEADER, then <version> will be included.
Otherwise, if __has_include is defined, that will be used to determine whether to include <version>.
| #define UGMISC_NO_CONSTEXPR_DESTRUCTORS |
This macro is never defined by features.hpp. If it is predefined before including features.hpp, or defined in the header indicated by UGMISC_PREDEFS_HEADER, it overrides the crude detection performed by features.hpp.
| #define UGMISC_PREDEFS_HEADER "quoted_header_name" |
This is not defined by features.hpp. If it is defined when features.hpp is included, features.hpp will include the header named by the macro like this:
Consequently, the header must expand to a name in quotes or angle brackets.