8

I'd like to use C++17's std::byte type if it's available, and fall back to using unsigned char if not, i.e. something along the lines of

#include <cstddef>

namespace my {
#if SOMETHING
using byte = std::byte;
#else
using byte = unsigned char;
#endif
}

Unfortunately it seems that std::byte didn't come come with the usual feature test macro, so it's not obvious what SOMETHING above should be. (AFAIK the value of __cplusplus for '17 hasn't been set yet, so I can't test for that either.)

So, does anybody know of a way to detect whether std::byte is available on the big three compilers?

Jan Schultke
  • 17,446
  • 6
  • 47
  • 96
Tristan Brindle
  • 16,281
  • 4
  • 39
  • 82
  • Boost might have you covered with [`boost::config`](http://www.boost.org/doc/libs/1_45_0/libs/config/doc/html/index.html) – NathanOliver Jun 12 '17 at 19:00
  • There is also `gsl::byte` https://github.com/Microsoft/GSL/tree/master/include/gsl – Galik Jun 12 '17 at 19:02
  • I deleted my answer because it is technically incorrect, though I'm almost certain it will work. Basically you can forward declare `std::byte`, and then detect whether or not it is complete. The problem is that even forward declaring a class from namespace `std` is technically UB. – Nir Friedman Jun 12 '17 at 19:16
  • 1
    Why? If `unsigned char` does what you need, use it. Otherwise you'll have two different sets of code to maintain. Don't jump through hoops to use the latest feature just because it's there. – Pete Becker Jun 12 '17 at 19:25
  • @Galik `gsl::byte` doesn't have the aliasing property `std::byte` has. That requires compiler support. – T.C. Jun 12 '17 at 20:14
  • @NirFriedman `std::byte` is a scoped enumeration, not a class. – T.C. Jun 12 '17 at 20:14
  • 2
    For C++17, `__cplusplus` is `201703L`. – T.C. Jun 12 '17 at 20:16
  • @T.C. I stand corrected. But the same technique can be made to work with the enum class, no? – Nir Friedman Jun 12 '17 at 20:17
  • @NirFriedman No, it can't. – T.C. Jun 12 '17 at 20:18
  • @T.C. I think I see. For anyone else: while it is possible to forward declare an enum class, I don't know if it's possible to detect whether an enum class is a complete or not. For a class one uses the fact that `sizeof` can only be called on complete classes, but for enums it seems like `sizeof` works on a forward declaration. – Nir Friedman Jun 12 '17 at 20:22
  • @T.C. Are you sure? It's underlying type is `unsigned char`, isn't that able to alias anything? – Galik Jun 12 '17 at 20:28
  • More to the point: an *opaque-enum-declaration* always declares a complete enumeration type with a fixed underlying type (`int` by default for scoped enums). An incomplete enumeration type is extremely rare and can only occur within its own definition. – T.C. Jun 12 '17 at 20:29
  • @Galik `unsigned char` can alias anything. "Enumeration type whose underlying type is `unsigned char`" is not "`unsigned char`" and doesn't alias everything (unless the standard by special rule says it does, which is the case for `std::byte`). – T.C. Jun 12 '17 at 20:30

2 Answers2

5

If you want to test availability of std::byte introduced by C++17, you should use __cpp_lib_byte macro (full list of feature testing macros is here).

The sample usage:

#include <iostream>
#include <cstddef>

#if __cpp_lib_byte
using byte = std::byte;
#else
using byte = unsigned char;
#endif

int main() {
    return 0; 
}
Barry
  • 286,269
  • 29
  • 621
  • 977
NutCracker
  • 11,485
  • 4
  • 44
  • 68
  • 1
    This is obviously the right way to do it today, but the `__cpp_lib_byte` macro didn't exist at the time I asked the question (or I wouldn't have bothered asking it!). It seems it was added at some point in the '20 development cycle. – Tristan Brindle Feb 20 '20 at 15:55
  • @TristanBrindle Yes. It must have been added recently. – NutCracker Feb 20 '20 at 16:26
3

For C++17, the value of __cplusplus is 201703L. But that's not super useful.

Instead, you should look at SD-6. This document contains all the feature test macros for all features adopted into C++, and the vendors all agree to follow them. It's possible that an implementation provides a feature but not the macro (e.g. gcc 7.2 supports std::byte but does not provide the macro) and more obviously that an implementation provides a feature and a macro but the feature is buggy, but you should rely on the macro. That's what it's there for.

Note that using unsigned char gives you almost the exact same behavior as std::byte - the only difference being that unsigned char supports extra arithmetic operations. So having an inexact check for std::byte support is okay - as long as you test on some compiler that supports std::byte to verify that you're not doing anything untoward, you're fine.

Barry
  • 286,269
  • 29
  • 621
  • 977
  • Note: the "SD Feature Test" (SD-6, https://isocpp.org/std/standing-documents/sd-6-sg10-feature-test-recommendations) link Barry cited above is still current as of Summer/2023. It was last updated 2023-08-12. – paulsm4 Aug 28 '23 at 17:50