Обработка буквального нуля в коде, безопасном для модуля

За очень немногими исключениями (глядя на вас, шкалы температур Фаренгейта и Цельсия), единицы являются линейными, и нулевое значение является одновременно аддитивным тождеством для всех единиц одновременно.

Так дано

auto speed = dimensioned(20, _meter/_second);
auto power = dimensioned(75, _watt);

затем

if (speed < 6) ...
if (power > 17) ...

не имеет больше смысла, чем

if (speed > power) ...

ты должен написать

if (speed < dimensioned(6, _mile/_hour)) ...

Тем не менее, это имеет смысл:

if (speed < 0)

потому что 0 м / с == 0 миль / ч == 0 а.е. / ночь или любые другие единицы, которые вы хотите использовать (для скорости). Вопрос в том, как включить это и только это использование.

C ++ 11 явные операторы и контекстное преобразование в bool избавился от необходимости идиомы «безопасный бул». Похоже, что эту проблему можно решить с помощью сопоставимой идиомы «безопасный ноль»:

struct X
{
int a;
friend bool operator<(const X& left, const X& right) { return left.a < right.a; }
private:
struct safe_zero_idiom;
public:
friend bool operator<(const X& left, safe_zero_idiom*) { return left.a < 0; }
};

К сожалению, похоже, что развернутые библиотеки измерений / единиц не делают этого. (Этот вопрос возник, потому что я действительно хотел проверить, является ли std::chrono::duration был отрицательным). Это полезно? Существуют ли случаи, которые могут привести к сбою? Есть ли более простой способ разрешить сравнение с нулем?

Можно предположить, что вместо реализации этого для отдельных операторов должно существовать неявное преобразование из буквального нуля в типы с тегами единиц.


Я отмечаю, что это позволяет

 X{1} < nullptr

как допустимое выражение 🙁 и, к сожалению, обеспечивающее недоступную перегрузку типа std::nullptr_t не исправляет это, так как Стандарт говорит в разделе 4.10

Константа нулевого указателя целочисленного типа может быть преобразована в тип значения std::nullptr_t,

10

Решение

  1. Да. Вы довольно легко убедили меня, что это полезно.
  2. Вы уже указали точку отказа, для nullptr, Я не мог думать ни о чем, кроме этого.
    Мои попытки разработать механизм, запрещающий nullptr но разрешить 0 все дало сложные схемы, которые не работали. По сути, поскольку нет никакого способа сказать C ++, что вы хотите constexpr Параметр функции, трудно (я пока не скажу невозможно …) разработать функцию, которая принимает int аргумент, но приводит к ошибке времени компиляции, если значение аргумента не 0,
  3. Если вы в порядке с разрешением nullptr, тогда более простая реализация будет использовать std::nullptr_t напрямую, а не отдельно safe_zero_idiom учебный класс. (Правда, это не так безопасно, так как нет никакого доступа к safe_zero_idiom введите вашу реализацию.)

struct X
{
int a;
friend bool operator<(const X& left, const X& right) { return left.a < right.a; }
friend bool operator<(const X& left, std::nullptr_t) { return left.a < 0; }
};
3

Другие решения

Я мог только придумать очевидное решение, которое отклоняется от того, что вы хотите:

#include <stdexcept>
#include <iostream>
#include <type_traits>
using namespace std;

#include <boost/mpl/int.hpp>

using namespace boost::mpl;

struct X
{
int a;

friend bool operator<(const X& left, const X& right)
{
return left.a < right.a;
}

template< typename T >
friend bool operator<(const X& left, T zero)
{
static_assert( is_same<int_<0>, T>::value, "cannot compare against arbitrary things");
return left.a < 0;
}
};

int_<0> unitless0;int main()
{
X x;

//if (x < 3) cout << "oopsie";  // we get a build error here as excpected.

if (x < unitless0)
cout << "ok";

return 0;
}
0

По вопросам рекламы [email protected]