12

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.

Sahib Yar
  • 1,030
  • 11
  • 29
M.M
  • 138,810
  • 21
  • 208
  • 365
  • "the current edition of godbolt gcc 9.3 `-std=c++2a` does not have `std::endian`" https://godbolt.org/z/aRFCps – cpplearner Apr 09 '20 at 06:29
  • 2
    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. – Miles Budnek Apr 09 '20 at 06:35
  • @cpplearner hmm weird, I did almost exactly the same thing and failed, oh well – M.M Apr 09 '20 at 06:39
  • 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](https://en.cppreference.com/w/cpp/types/endian) proposes as an implementation. – selbie Apr 09 '20 at 06:51
  • @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](https://stackoverflow.com/questions/10711952/how-to-detect-existence-of-a-class-using-sfinae) only works for classes, not enums – M.M Apr 09 '20 at 07:23
  • @M.M Isn't std::endian an enum class? One of the solutions should apply to it. Did you check it? – freakish Apr 09 '20 at 07:46
  • @freakish "enum class" is still an enum, not a class – M.M Apr 09 '20 at 07:55
  • 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. – MSalters Apr 09 '20 at 08:30
  • @MSalters I haven't been able to get anything along those lines to work yet , e.g. https://godbolt.org/z/9uuaEL – M.M Apr 09 '20 at 08:42
  • 1
    I do not think you can have `constexpr` and `runtime_detection()` on the same line ;-) – Krzysiek Karbowiak Apr 09 '20 at 13:11

1 Answers1

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;
Barry
  • 286,269
  • 29
  • 621
  • 977
  • maybe this needs a tweak, `runtime_detection()` should not be assigned to a constexpr variable – M.M Apr 10 '20 at 07:58