Как проверить битовый шаблон двойного 0x0 в constexpr C ++ 11? - PullRequest
9 голосов
/ 17 февраля 2012

Я хочу проверить, что данная переменная типа double / float имеет фактическую битовую комбинацию 0x0.Не спрашивайте почему, он используется в функции в Qt (qIsNull()), которой я хотел бы быть constexpr.

В исходном коде использовалось объединение:

union { double d; int64_t i; } u;
u.d = d;
return u.i == 0;

Это не работает как constexpr конечно.

Следующая попытка была с reinterpret_cast:

return *reinterpret_cast<int64_t*>(&d) == 0;

Но пока это работает как constexpr в GCC 4.7, он терпит неудачу (по праву, b / c манипулирования указателем) в Clang 3.1.

Последняя идея состояла в том, чтобы перейти к Александреску и сделать это:

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);

Но это не достаточно умно для Clangлибо:

note: read of member 't2' of union with active member 't1' is not allowed in a constant expression
constexpr operator T2() const { return t2; }
                                       ^

У кого-нибудь еще есть хорошая идея?

Ответы [ 3 ]

6 голосов
/ 17 февраля 2012

Я хочу проверить, что данная переменная типа double / float имеет фактическую битовую комбинацию 0x0

Но если это constexpr, то она не проверяет любую переменную он проверяет значение , что эта переменная статически определена для хранения.Вот почему вы не должны использовать приемы указателя и объединения, «официально» нет никакой памяти, на которую можно было бы указать.

Если вы можете убедить свою реализацию сделать не перехватывание IEEE с делением на ноль, тогда вы можете сделать что-то вроде:

return (d == 0) && (1 / d > 0)

Только +/-0 равно 0. 1/-0 равно -Inf, что не больше 0. 1/+0 равно +Inf,который.Но я не знаю, как заставить эту арифметику без ловушек произойти.

5 голосов
/ 17 февраля 2012

Кажется, что и clang ++ 3.0, и g ++ 4.7 (но не 4.6) рассматривают std::signbit как constexpr.

return x == 0 && std::signbit(x) == 0;
4 голосов
/ 02 марта 2012

Невозможно посмотреть базовый битовый шаблон double из константного выражения. В стандарте C ++ 11 был дефект, который позволял проводить такую ​​проверку путем приведения через void*, но это было устранено с помощью C ++ core1312 .

Как «доказательство», реализация constexpr от clang (которая считается завершенной) не имеет механизма для извлечения представления постоянного значения double (кроме как посредством нестандартных векторных операций, и даже тогда есть в настоящее время нет возможности проверить результат).

Как и другие предлагали, если вы знаете, что будете ориентироваться на платформу, которая использует плавающую точку IEEE-754, 0x0 соответствует значению положительный ноль. Я считаю, что единственный способ обнаружить это, который работает внутри константного выражения в clang и g ++, это использовать __builtin_copysign:

constexpr bool isPosZero(double d) {
  return d == 0.0 && __builtin_copysign(1.0, d) == 1.0;
}
...