Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to use std::endian if it is available, otherwise do something else?

Since C++20 we can have:

constexpr bool is_little_endian = std::endian::native == std::endian::little;

I would like to have code that does this if it is available, otherwise does runtime detection. Is this possible?

Maybe the code would look like:

template<bool b = std_endian_exists_v> constexpr bool is_little_endian;
template<> constexpr bool is_little_endian<true> = std::endian::native == std::endian::little;
template<> constexpr bool is_little_endian<false> = runtime_detection();

I am aware that testing __cplusplus via preprocessor is possible, however compilers phase in C++20 support in various stages so this is not a reliable indicator in either direction.

like image 805
M.M Avatar asked Apr 09 '20 06:04

M.M


1 Answers

I am aware that testing __cplusplus via preprocessor is possible, however compilers phase in C++20 support in various stages so this is not a reliable indicator in either direction.

Indeed! In fact, this is why we now have an entirely new method of detecting feature support for compilers that are in various stages of release: feature-test macros! If you look at SD-FeatureTest, there are large tables of macros corresponding to each language and library feature adopted into the standard, where each macro will be defined with the specified value once a feature is adopted.

In your specific case, you want __cpp_lib_endian.

Now the problem with library macros is that we started added them before we added a place to put them - which would be <version>. If you're on a compiler that has <version> (which would be gcc 9+, clang 7+ with libc++, and I don't know about MSVC), you can just include that. But it might not, so you might also have to try to include the correct header (in this case <bit>).

#if __has_include(<bit>)
#  include <bit>
#  ifdef __cpp_lib_endian
#    define HAS_ENDIAN 1
#  endif
#endif

#ifdef HAS_ENDIAN
constexpr bool is_little_endian = std::endian::native == std::endian::little;
#else
constexpr bool is_little_endian = /* ... figure it out ... */;
#endif

Although it might be better to do:

#ifdef HAS_ENDIAN
using my_endian = std::endian;
#else
enum class my_endian {
   // copy some existing implementation
};
#endif

constexpr bool is_little_endian = my_endian::native == my_endian::little;
like image 89
Barry Avatar answered Oct 28 '22 07:10

Barry