constexpr and endianness - c++

A common question that comes up from time to time in the world of C++ programming is compile-time determination of endianness. Usually this is done with barely portable #ifdefs. But does the C++11 constexpr keyword along with template specialization offer us a better solution to this?
Would it be legal C++11 to do something like:
constexpr bool little_endian()
{
const static unsigned num = 0xAABBCCDD;
return reinterpret_cast<const unsigned char*> (&num)[0] == 0xDD;
}
And then specialize a template for both endian types:
template <bool LittleEndian>
struct Foo
{
// .... specialization for little endian
};
template <>
struct Foo<false>
{
// .... specialization for big endian
};
And then do:
Foo<little_endian()>::do_something();

New answer (C++20)
c++20 has introduced a new standard library header <bit>.
Among other things it provides a clean, portable way to check the endianness.
Since my old method relies on some questionable techniques, I suggest anyone who uses it to switch to the check provided by the standard library.
Here's an adapter which allows to use the new way of checking endianness without having to update the code that relies on the interface of my old class:
#include <bit>
class Endian
{
public:
Endian() = delete;
static constexpr bool little = std::endian::native == std::endian::little;
static constexpr bool big = std::endian::native == std::endian::big;
static constexpr bool middle = !little && !big;
};
Old answer
I was able to write this:
#include <cstdint>
class Endian
{
private:
static constexpr uint32_t uint32_ = 0x01020304;
static constexpr uint8_t magic_ = (const uint8_t&)uint32_;
public:
static constexpr bool little = magic_ == 0x04;
static constexpr bool middle = magic_ == 0x02;
static constexpr bool big = magic_ == 0x01;
static_assert(little || middle || big, "Cannot determine endianness!");
private:
Endian() = delete;
};
I've tested it with g++ and it compiles without warnings. It gives a correct result on x64.
If you have any big-endian or middle-endian proccesor, please, confirm that this works for you in a comment.

It is not possible to determine endianness at compile time using constexpr (before C++20). reinterpret_cast is explicitly forbidden by [expr.const]p2, as is iain's suggestion of reading from a non-active member of a union. Casting to a different reference type is also forbidden, as such a cast is interpreted as a reinterpret_cast.
Update:
This is now possible in C++20. One way (live):
#include <bit>
template<std::integral T>
constexpr bool is_little_endian() {
for (unsigned bit = 0; bit != sizeof(T) * CHAR_BIT; ++bit) {
unsigned char data[sizeof(T)] = {};
// In little-endian, bit i of the raw bytes ...
data[bit / CHAR_BIT] = 1 << (bit % CHAR_BIT);
// ... corresponds to bit i of the value.
if (std::bit_cast<T>(data) != T(1) << bit)
return false;
}
return true;
}
static_assert(is_little_endian<int>());
(Note that C++20 guarantees two's complement integers -- with an unspecified bit order -- so we just need to check that every bit of the data maps to the expected place in the integer.)
But if you have a C++20 standard library, you can also just ask it:
#include <type_traits>
constexpr bool is_little_endian = std::endian::native == std::endian::little;

Assuming N2116 is the wording that gets incorporated, then your example is ill-formed (notice that there is no concept of "legal/illegal" in C++). The proposed text for [decl.constexpr]/3 says
its function-body shall be a compound-statement of the form
{ return expression; }
where expression is a potential constant expression (5.19);
Your function violates the requirement in that it also declares a local variable.
Edit: This restriction could be overcome by moving num outside of the function. The function still wouldn't be well-formed, then, because expression needs to be a potential constant expression, which is defined as
An expression is a potential constant expression if it is a constant
expression when all occurrences of function parameters are replaced
by arbitrary constant expressions of the appropriate type.
IOW, reinterpret_cast<const unsigned char*> (&num)[0] == 0xDD would have to be a constant expression. However, it is not: &num would be a address constant-expression (5.19/4). Accessing the value of such a pointer is, however, not allowed for a constant expression:
The subscripting operator [] and the class member access . and
operators, the & and * unary operators, and pointer casts (except dynamic_casts, 5.2.7) can be used in the creation of an
address constant expression, but the value of an object shall not be accessed by the use of these operators.
Edit: The above text is from C++98. Apparently, C++0x is more permissive what it allows for constant expressions. The expression involves an lvalue-to-rvalue conversion of the array reference, which is banned from constant expressions unless
it is applied to an lvalue of effective integral type that refers
to a non-volatile const variable or static data member initialized
with constant expressions
It's not clear to me whether (&num)[0] "refers to" a const variable, or whether only a literal num "refers to" such a variable. If (&num)[0] refers to that variable, it is then unclear whether reinterpret_cast<const unsigned char*> (&num)[0] still "refers to" num.

There is std::endian in the upcoming C++20.
#include <bit>
constexpr bool little_endian() noexcept
{
return std::endian::native == std::endian::little;
}

My first post. Just wanted to share some code that I'm using.
//Some handy defines magic, thanks overflow
#define IS_LITTLE_ENDIAN ('ABCD'==0x41424344UL) //41 42 43 44 = 'ABCD' hex ASCII code
#define IS_BIG_ENDIAN ('ABCD'==0x44434241UL) //44 43 42 41 = 'DCBA' hex ASCII code
#define IS_UNKNOWN_ENDIAN (IS_LITTLE_ENDIAN == IS_BIG_ENDIAN)
//Next in code...
struct Quad
{
union
{
#if IS_LITTLE_ENDIAN
struct { std::uint8_t b0, b1, b2, b3; };
#elif IS_BIG_ENDIAN
struct { std::uint8_t b3, b2, b1, b0; };
#elif IS_UNKNOWN_ENDIAN
#error "Endianness not implemented!"
#endif
std::uint32_t dword;
};
};
Constexpr version:
namespace Endian
{
namespace Impl //Private
{
//41 42 43 44 = 'ABCD' hex ASCII code
static constexpr std::uint32_t LITTLE_{ 0x41424344u };
//44 43 42 41 = 'DCBA' hex ASCII code
static constexpr std::uint32_t BIG_{ 0x44434241u };
//Converts chars to uint32 on current platform
static constexpr std::uint32_t NATIVE_{ 'ABCD' };
}
//Public
enum class Type : size_t { UNKNOWN, LITTLE, BIG };
//Compare
static constexpr bool IS_LITTLE = Impl::NATIVE_ == Impl::LITTLE_;
static constexpr bool IS_BIG = Impl::NATIVE_ == Impl::BIG_;
static constexpr bool IS_UNKNOWN = IS_LITTLE == IS_BIG;
//Endian type on current platform
static constexpr Type NATIVE_TYPE = IS_LITTLE ? Type::LITTLE : IS_BIG ? Type::BIG : Type::UNKNOWN;
//Uncomment for test.
//static_assert(!IS_LITTLE, "This platform has little endian.");
//static_assert(!IS_BIG, "This platform has big endian.");
//static_assert(!IS_UNKNOWN, "Error: Unsupported endian!");
}

That is a very interesting question.
I am not Language Lawyer, but you might be able to replace the reinterpret_cast with a union.
const union {
int int_value;
char char_value[4];
} Endian = { 0xAABBCCDD };
constexpr bool little_endian()
{
return Endian[0] == 0xDD;
}

This may seem like cheating, but you can always include endian.h... BYTE_ORDER == BIG_ENDIAN is a valid constexpr...

Here is a simple C++11 compliant version, inspired by #no-name answer:
constexpr bool is_system_little_endian(int value = 1) {
return static_cast<const unsigned char&>(value) == 1;
}
Using a default value to crank everything on one line is to meet C++11 requirements on constexpr functions: they must only contain a single return statement.
The good thing with doing it (and testing it!) in a constexpr context is that it makes sure that there is no undefined behavior in the code.
On compiler explorer here.

If your goal is to insure that the compiler optimizes little_endian() into a constant true or false at compile-time, without any of its contents winding up in the executable or being executed at runtime, and only generating code from the "correct" one of your two Foo templates, I fear you're in for a disappointment.
I also am not a language lawyer, but it looks to me like constexpr is like inline or register: a keyword that alerts the compiler writer to the presence of a potential optimization. Then it's up to the compiler writer whether or not to take advantage of that. Language specs typically mandate behaviors, not optimizations.
Also, have you actually tried this on a variety of C++0x complaint compilers to see what happens? I would guess most of them would choke on your dual templates, since they won't be able to figure out which one to use if invoked with false.

Related

Type Punning via constexpr union

I am maintaining an old code base, that is using a union of an integer type with a bit-field struct for type-punning. My compiler is VS2017. As an example, the code is similar to the following:
struct FlagsType
{
unsigned flag0 : 1;
unsigned flag1 : 1;
unsigned flag2 : 1;
};
union FlagsTypeUnion
{
unsigned flagsAsInt;
FlagsType flags;
};
bool isBitSet(unsigned flagNum, FlagsTypeUnion flags)
{
return ((1u << flagNum) & flags.flagsAsInt);
}
This code has a number of undefined behavior issues. Namely, it is hotly debated whether type punning is defined behavior or not, but on top of that, the implementation of packing bit-fields is implementation-defined. To address these issues, I would like to add static-assert statements to validate that the VS implementation enables using this type of approach. However, when I tried to add the following code, I get error C2131: expression did not evaluate to a constant.
union FlagsTypeUnion
{
unsigned flagsAsInt;
FlagsType flags;
constexpr FlagsTypeUnion(unsigned const f = 0) : flagsAsInt{ f } {}
};
static_assert(FlagsTypeUnion{ 1 }.flags.flag0,
"The code currently assumes bit-fields are packed from LSB to MSB");
Is there any way to add compile-time checks to verify the type-punning and bit-packing code works as the runtime code is assuming? Unfortunately, this code is spread throughout the code base, so changing the structures isn't really feasible.
You might use std::bit_cast (C++20):
struct FlagsType
{
unsigned flag0 : 1;
unsigned flag1 : 1;
unsigned flag2 : 1;
unsigned padding : 32 - 3; // Needed for gcc
};
static_assert(std::is_trivially_constructible_v<FlagsType>);
constexpr FlagsType makeFlagsType(bool flag0, bool flag1, bool flag2)
{
FlagsType res{};
res.flag0 = flag0;
res.flag1 = flag1;
res.flag2 = flag2;
return res;
}
static_assert(std::bit_cast<unsigned>(makeFlagsType(true, false, false)) == 1);
Demo
clang doesn't support it (yet) though.
gcc requires to add explicitly the padding bits for the constexpr check.

Compile-time detection of overflow in bitmask

I'm toying with a general Bitmask class, based on Type-safe Bitmasks in C++, and here is a minimum example highligthning my issue (Compiler Explorer link here):
#include <type_traits>
#include <cstdint>
#include <iostream>
template<class EnumType,
// Ensure that Bitmask can only be used with enums
typename = std::enable_if_t<std::is_enum_v<EnumType>>>
class Bitmask
{
// Type to store bitmask. Should possibly be bigger
using underlying_type = std::underlying_type_t<EnumType>;
public:
constexpr Bitmask(EnumType option) : m_mask(bitmaskValue(option))
{std::cout << "Bitmask " << (int)m_mask << "\n";}
private:
// m_mask holds the underlying value, e.g. 2 to the power of enum value underlying_type
m_mask{0};
static constexpr underlying_type bitmaskValue(EnumType o)
{ return 1 << static_cast<underlying_type>(o); }
explicit constexpr Bitmask(underlying_type o) : m_mask(o) {}
};
enum class Option : uint8_t
{
a, b, c, d, e, f, g, h, i
};
enum class Option2 : int
{
a, b, c, d, e, f, g, h, i
};
int main()
{
Bitmask<Option> b1{Option::a};
Bitmask<Option> b2{Option::h};
Bitmask<Option> b3{Option::i};
Bitmask<Option2> b4{Option2::i};
}
// Output
Bitmask 1
Bitmask 128
Bitmask 0
Bitmask 256
In short, the Bitmask type works fine as long as the underlying type has more bits than the highest enum value used. If not, the bitmaskValue function will overflow and not give desired result, as shown in output, where b3 gets a value of 0, not 256.
I of course understand that an uint8_t cannot store more than 8 different bits, so what I want is some way to make this a compiler error, either when declaring Bitmask<Option>, or when instatiating a Bitmask with a too high value.
I tried changing the bitmaskValue method to:
static constexpr underlying_type bitmaskValue(EnumType o) {
if constexpr (std::numeric_limits<underlying_type>::digits >= static_cast<underlying_type>(o)) {
return 1 << static_cast<underlying_type>(o);
} else {
// some error
}
}
...but then I get the error that 'o' is not a constant expression.
Can anyone helpt me in the correct direction here? For the record, our project is currently using gcc 9.2/c++17, though I hope we can soon upgrade to gcc 11.1/c++20.
Thanks.
As Davis Herring already pointed out you cannot check for the overflow on a non-constant value at runtime (constexpr marked functions may also be executed at runtime). Thus to get the desired functionality one could check for the overflow inside the declaration of a template with the value to test as non-type template parameter.
The basic idea is that with brace initialization with a constant value, the compiler will generate a compilation error when the cast is narrowing, e.g. int8_t{128}; will fail since 128 cannot be represented with int8_t.
template<class EnumType>
class Bitmask
{
using underlying_type = std::underlying_type_t<EnumType>;
public:
explicit constexpr Bitmask(underlying_type v) : m_mask{v} {}
constexpr Bitmask(EnumType option) : m_mask{0x1 << static_cast<underlying_type>(option)}{}
template <EnumType option> // <- enum value as non-type template parameter
static constexpr auto make()
{
return Bitmask{underlying_type{0x1 << static_cast<underlying_type>(option)}};
}
underlying_type m_mask{0};
};
enum class Option : uint8_t
{
a, b, c, d, e, f, g, h, i
};
Bitmask<Option>::make<Option::f>(); // ok
Bitmask<Option>::make<Option::h>(); // ok
// Bitmask<Option>::make<Option::i>(); // will fail to build
https://godbolt.org/z/117baa4q4
If you control the enum definition as well, the simplest way is just to require an enumerated constant with a fixed name at the end (ie, so it is the largest real value + 1), such as EnumType::MAX_ENUM_VALUE.
Then you can refuse to instantiate if
EnumType::MAX_ENUM_VALUE > std::numeric_limits<underlying_type>::digits + 1
with a static assert, or an enable_if, or whatever. Obviously this will also fail to instantiate if the enumerated constant is missing, so it should be pretty obvious to the user how to fix it.
Note this isn't really a compile-time check for overflow, but for the possibility of overflow. So, it is on the strict side if you only use a subset of your enum's values - but it is consistent with the goal of type safety.

C++ enum flags vs bitset

What are pros/cons of usage bitsets over enum flags?
namespace Flag {
enum State {
Read = 1 << 0,
Write = 1 << 1,
Binary = 1 << 2,
};
}
namespace Plain {
enum State {
Read,
Write,
Binary,
Count
};
}
int main()
{
{
unsigned int state = Flag::Read | Flag::Binary;
std::cout << state << std::endl;
state |= Flag::Write;
state &= ~(Flag::Read | Flag::Binary);
std::cout << state << std::endl;
} {
std::bitset<Plain::Count> state;
state.set(Plain::Read);
state.set(Plain::Binary);
std::cout << state.to_ulong() << std::endl;
state.flip();
std::cout << state.to_ulong() << std::endl;
}
return 0;
}
As I can see so far, bitsets have more convinient set/clear/flip functions to deal with, but enum-flags usage is a more wide-spreaded approach.
What are possible downsides of bitsets and what and when should I use in my daily code?
Both std::bitset and c-style enum have important downsides for managing flags. First, let's consider the following example code :
namespace Flag {
enum State {
Read = 1 << 0,
Write = 1 << 1,
Binary = 1 << 2,
};
}
namespace Plain {
enum State {
Read,
Write,
Binary,
Count
};
}
void f(int);
void g(int);
void g(Flag::State);
void h(std::bitset<sizeof(Flag::State)>);
namespace system1 {
Flag::State getFlags();
}
namespace system2 {
Plain::State getFlags();
}
int main()
{
f(Flag::Read); // Flag::Read is implicitly converted to `int`, losing type safety
f(Plain::Read); // Plain::Read is also implicitly converted to `int`
auto state = Flag::Read | Flag::Write; // type is not `Flag::State` as one could expect, it is `int` instead
g(state); // This function calls the `int` overload rather than the `Flag::State` overload
auto system1State = system1::getFlags();
auto system2State = system2::getFlags();
if (system1State == system2State) {} // Compiles properly, but semantics are broken, `Flag::State`
std::bitset<sizeof(Flag::State)> flagSet; // Notice that the type of bitset only indicates the amount of bits, there's no type safety here either
std::bitset<sizeof(Plain::State)> plainSet;
// f(flagSet); bitset doesn't implicitly convert to `int`, so this wouldn't compile which is slightly better than c-style `enum`
flagSet.set(Flag::Read); // No type safety, which means that bitset
flagSet.reset(Plain::Read); // is willing to accept values from any enumeration
h(flagSet); // Both kinds of sets can be
h(plainSet); // passed to the same function
}
Even though you may think those problems are easy to spot on simple examples, they end up creeping up in every code base that builds flags on top of c-style enum and std::bitset.
So what can you do for better type safety? First, C++11's scoped enumeration is an improvement for type safety. But it hinders convenience a lot. Part of the solution is to use template-generated bitwise operators for scoped enums. Here is a great blog post which explains how it works and also provides working code : https://www.justsoftwaresolutions.co.uk/cplusplus/using-enum-classes-as-bitfields.html
Now let's see what this would look like :
enum class FlagState {
Read = 1 << 0,
Write = 1 << 1,
Binary = 1 << 2,
};
template<>
struct enable_bitmask_operators<FlagState>{
static const bool enable=true;
};
enum class PlainState {
Read,
Write,
Binary,
Count
};
void f(int);
void g(int);
void g(FlagState);
FlagState h();
namespace system1 {
FlagState getFlags();
}
namespace system2 {
PlainState getFlags();
}
int main()
{
f(FlagState::Read); // Compile error, FlagState is not an `int`
f(PlainState::Read); // Compile error, PlainState is not an `int`
auto state = FlagState::Read | FlagState::Write; // type is `FlagState` as one could expect
g(state); // This function calls the `FlagState` overload
auto system1State = system1::getFlags();
auto system2State = system2::getFlags();
if (system1State == system2State) {} // Compile error, there is no `operator==(FlagState, PlainState)`
auto someFlag = h();
if (someFlag == FlagState::Read) {} // This compiles fine, but this is another type of recurring bug
}
The last line of this example shows one problem that still cannot be caught at compile time. In some cases, comparing for equality may be what's really desired. But most of the time, what is really meant is if ((someFlag & FlagState::Read) == FlagState::Read).
In order to solve this problem, we must differentiate the type of an enumerator from the type of a bitmask. Here's an article which details an improvement on the partial solution I referred to earlier : https://dalzhim.github.io/2017/08/11/Improving-the-enum-class-bitmask/
Disclaimer : I'm the author of this later article.
When using the template-generated bitwise operators from the last article, you will get all of the benefits we demonstrated in the last piece of code, while also catching the mask == enumerator bug.
Some observations:
std::bitset< N > supports an arbitrary number of bits (e.g., more than 64 bits), whereas underlying integral types of enums are restricted to 64 bits;
std::bitset< N > can implicitly (depending on the std implementation) use the underlying integral type with the minimal size fitting the requested number of bits, whereas underlying integral types for enums need to be explicitly declared (otherwise, int will be used as the default underlying integral type);
std::bitset< N > represents a generic sequence of N bits, whereas scoped enums provide type safety that can be exploited for method overloading;
If std::bitset< N > is used as a bit mask, a typical implementation depends on an additional enum type for indexing (!= masking) purposes;
Note that the latter two observations can be combined to define a strong std::bitset type for convenience:
typename< Enum E, std::size_t N >
class BitSet : public std::bitset< N >
{
...
[[nodiscard]]
constexpr bool operator[](E pos) const;
...
};
and if the code supports some reflection to obtain the number of explicit enum values, then the number of bits can be deduced directly from the enum type.
scoped enum types do not have bitwise operator overloads (which can easily be defined once using SFINAE or concepts for all scoped and unscoped enum types, but need to be included before use) and unsoped enum types will decay to the underlying integral type;
bitwise operator overloads for enum types, require less boilerplate than std::bitset< N > (e.g., auto flags = Depth | Stencil;);
enum types support both signed and unsigned underlying integral types, whereas std::bitset< N > internally uses unsigned integral types (shift operators).
FWIIW, in my own code I mostly use std::bitset (and eastl::bitvector) as private bit/bool containers for setting/getting single bits/bools. For masking operations, I prefer scoped enum types with explicitly defined underlying types and bitwise operator overloads.
Do you compile with optimization on? It is very unlikely that there is a 24x speed factor.
To me, bitset is superior, because it manages space for you:
can be extended as much as wanted. If you have a lot of flags, you may run out of space in the int/long long version.
may take less space, if you only use just several flags (it can fit in an unsigned char/unsigned short - I'm not sure that implementations apply this optimization, though)
(Ad mode on)
You can get both: a convenient interface and max performance. And type-safety as well. https://github.com/oliora/bitmask

How do I access a constexpr created type as another type while staying constexpr? (using with static_assert)

I've been trying to figure this one out, and thought it would be a fun one to take a look at :)
Ok, so I'm creating a type as constexpr using bitfields. Since bitfields can change from one implementation or platform to another, I want to static_assert that the bits are in the right place. With me so far? Here's the code for the type I'm creating:
// Currently hard-coded for 64bit, will change later when I get past this part...
constexpr int getPointerBitCount() { return 64; }
constexpr int getPointerByteWidth() { return getPointerBitCount() / 8; }
constexpr int getPointerDataWidth() { return 3; }
constexpr int getPointerPointerWidth() { return getPointerBitCount() - getPointerDataWidth(); }
struct PointerData
{
bool _invalid :1;
bool _delete :1;
bool _unused :1;
uint64_t _pointer :getPointerPointerWidth();
constexpr PointerData(bool invalid, bool isDelete, bool unused)
: _invalid{invalid}
, _delete{isDelete}
, _unused{unused}
, _pointer{0}
{
}
};
So now what I would like to do is this:
static_assert(reinterpret_cast<uint64_t>(PointerData(true, false, false)) == 1, "PointerData not supported on this platform");
static_assert(reinterpret_cast<uint64_t>(PointerData(false, true, false)) == 2, "PointerData not supported on this platform");
static_assert(reinterpret_cast<uint64_t>(PointerData(false, false, true)) == 4, "PointerData not supported on this platform");
Basically, I need to create the PointerData type as constexpr, and then run tests on it as if the entire thing was a uint64_t (or uint32_t on 32 bit). But, my compiler says I can't use reinterpret_cast here. Thoughts on how I can do this?
Running bitwise operators to compute the value will not achieve what I'm looking for. I need to access the variable "as is". The test here is to see if the first bit in a bitfield is equal to 1. (and the second = 2, and the 3rd = 4).
I looked into creating a union out of this, but I'm not sure if that's appropriate given the bitfields. Unsure.
I'm new to the constexpr stuff, so help would be appreciated!
reinterpret_cast is not compatible with static_assert, even when its behavior is well-defined, but your usage has implementation-specific behavior. The compiler would be allowed to reject such code, or the machine would be allowed to crash and burn if you execute such a cast.
To get it to work, add a constexpr operator uint64_t () const to PointerData which returns the value you expect the reinterpret_cast to yield. Then change the reinterpret_cast to static_cast.
EDIT: No, C++ does not support what you are attempting. Constant expression evaluation (as in constexpr) asks the compiler to emulate the target platform to a certain degree. This emulator is required to flag undefined behavior as an error, as well as many implementation-specific cases including all reinterpret_cast expressions.
The architecture of your reinterpret_cast doesn't work because it is performing its introspection inside an emulator. You need to move it to a build system "canary" or program startup instead.

How to check a double's bit pattern is 0x0 in a C++11 constexpr?

I want to check that a given double/float variable has the actual bit pattern 0x0. Don't ask why, it's used in a function in Qt (qIsNull()) that I'd like to be constexpr.
The original code used a union:
union { double d; int64_t i; } u;
u.d = d;
return u.i == 0;
This doesn't work as a constexpr of course.
The next try was with reinterpret_cast:
return *reinterpret_cast<int64_t*>(&d) == 0;
But while that works as a constexpr in GCC 4.7, it fails (rightfully, b/c of pointer manipulation) in Clang 3.1.
The final idea was to go Alexandrescuesque and do this:
template <typename T1, typename T2>
union Converter {
T1 t1;
T2 t2;
explicit constexpr Converter( T1 t1 ) : t1(t1) {}
constexpr operator T2() const { return t2; }
};
// in qIsNull():
return Converter<double,int64_t>(d);
But that's not clever enough for Clang, either:
note: read of member 't2' of union with active member 't1' is not allowed in a constant expression
constexpr operator T2() const { return t2; }
^
Does anyone else have a good idea?
I want to check that a given double/float variable has the actual bit pattern 0x0
But if it's constexpr then it's not checking any variable, it's checking the value that this variable is statically determined to hold. That's why you aren't supposed to pull pointer and union tricks, "officially" there isn't any memory to point at.
If you can persuade your implementation to do non-trapping IEEE division-by-zero, then you could do something like:
return (d == 0) && (1 / d > 0)
Only +/-0 are equal to 0. 1/-0 is -Inf, which isn't greater than 0. 1/+0 is +Inf, which is. But I don't know how to make that non-trapping arithmetic happen.
It seems both clang++ 3.0 and g++ 4.7 (but not 4.6) treats std::signbit as constexpr.
return x == 0 && std::signbit(x) == 0;
It is not possible to look at the underlying bit pattern of a double from within a constant expression. There was a defect in the C++11 standard which allowed such inspection by casting via a void*, but that was addressed by C++ core issue 1312.
As "proof", clang's constexpr implementation (which is considered to be complete) has no mechanism for extracting the representation of a constant double value (other than via non-standard vector operations, and even then there is currently no way to inspect the result).
As others have suggested, if you know you will be targeting a platform which uses IEEE-754 floating point, 0x0 corresponds to the value positive zero. I believe the only way to detect this, that works inside a constant expression in both clang and g++, is to use __builtin_copysign:
constexpr bool isPosZero(double d) {
return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}