Вы не можете реально представить его в одном и том же количестве бит без часового.Если 0 является действительным числом, то вы не можете его использовать.Если вы попытаетесь навязать нулевую обработку типу значения, у вас будет принципиально неверный и не поддерживаемый код.
При правильной обработке нулей вы ожидаете увидеть такой интерфейс:
struct foo {
virtual ~foo() {}
virtual bool getX(double &val) = 0;
virtual bool getY(double &val) = 0;
virtual bool getZ(double &val) = 0;
};
У реализации может быть флаг, который она проверяет перед доступом.
void some_func(foo *f) {
double x, y, z;
if (f->getX(x) && f->getY(y) && f->getZ(z)) {
cout << x << ", " << y << ", " << z << endl;
} else {
throw std::logic_error("expected some values here");
}
}
Вы не хотите использовать недопустимое значение и не знаете его.Необходимость проверки возвращаемых значений, очевидно, утомительна, но дает вам максимальный контроль.У вас также могут быть помощники или перегрузки, которые будут выдавать, если они недействительны.
struct bar {
double getX() {
if (!valid)
throw std::logic_error("bar is not valid");
return x;
}
bool valid;
double x, y, z;
}
Для меня разница между foo
и bar
заключается в том, что низкоуровневый код, обрабатывающий данные, не долженпроводить политику того, есть ли данные там или нет.На более высоких уровнях абстракции вы можете и должны иметь ожидания относительно того, должны ли данные быть действительными, когда вы собираетесь их использовать.Оба могут существовать в системе, но foo
необходимо.