За очень немногими исключениями (глядя на вас, шкалы температур Фаренгейта и Цельсия), единицы являются линейными, и нулевое значение является одновременно аддитивным тождеством для всех единиц одновременно.
Так дано
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
,
nullptr
, Я не мог думать ни о чем, кроме этого.nullptr
но разрешить 0
все дало сложные схемы, которые не работали. По сути, поскольку нет никакого способа сказать C ++, что вы хотите constexpr
Параметр функции, трудно (я пока не скажу невозможно …) разработать функцию, которая принимает int
аргумент, но приводит к ошибке времени компиляции, если значение аргумента не 0
,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; }
};
Я мог только придумать очевидное решение, которое отклоняется от того, что вы хотите:
#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;
}