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

1

13

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.

Tropophilous answered 9/4, 2020 at 6:7 Comment(10)
"the current edition of godbolt gcc 9.3 -std=c++2a does not have std::endian" godbolt.org/z/aRFCpsMelisandra
You could have your build system detect it by attempting to compile a test program that uses std::endian and then conditionally defining a preprocessor symbol, but I have a feeling that's not the answer you're looking for.Pulvinate
@Melisandra hmm weird, I did almost exactly the same thing and failed, oh wellTropophilous
I was about to propose a cough preprocessor solution that would check for VC++ vs g++ defines. But I suspect you want a universal solution. Ironically, that's what the reference page proposes as an implementation.Esqueda
@MilesBudnek Hmm.. I guess this question is then equivalent to "how to detect existence of an enum". Unfortunately the solution in How to detect existence of a class only works for classes, not enumsTropophilous
@Tropophilous Isn't std::endian an enum class? One of the solutions should apply to it. Did you check it?Money
@Money "enum class" is still an enum, not a classTropophilous
I'm thinking about name lookup tricks. using namespace std; will allow unqualified endian to find std::endian if that exists. If not, endian is looked up in the surrounding namespace.Ogle
@Ogle I haven't been able to get anything along those lines to work yet , e.g. godbolt.org/z/9uuaELTropophilous
I do not think you can have constexpr and runtime_detection() on the same line ;-)Pneumoconiosis
A
10

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;
Atelectasis answered 9/4, 2020 at 13:30 Comment(1)
maybe this needs a tweak, runtime_detection() should not be assigned to a constexpr variableTropophilous

© 2022 - 2024 — McMap. All rights reserved.