Как записать численно в символ? Правильно, что бы обнаружить переполнения?

ПОЛНОСТЬЮ ВОССТАНОВИЛ ВОПРОС.

Я хотел бы написать численно в целочисленный тип, не будучи уверенным, действительно ли это тип символа: char, wchar_t, char32_t и т.п.

Рассмотрим следующий код:

template <typename T> class MyInteger
{
  T value;
public:
  MyInteger() : value{0} {}

  friend istream &operator >> (istream &in, MyInteger &i)
  {
    in >> i.value;
    return in;
  }

  friend ostream &operator << (ostream &out, const MyInteger &i)
  {
    out << i.value;
    return out;
  }
};

Я хочу, чтобы такой класс правильно обрабатывал все целочисленные типы, включая, например, int_least8_t который может (если не гарантирован) оценить char,

Приведенный выше код не работает с этой целью. Давайте предположим, что параметр шаблона T установлен в char (например, позволяя компилятору оценить int_least8_t). Предоставление этой программы ввода 25 приведет к персонажу 5 оставаясь во входном потоке, и value будет присвоен код ASCII2 (что бывает 50). Это явно неправильно. Точно так же, заставляя эту программу печатать value из 50 приведет к 2 печатается вместо.

Одним из очевидных решений является Typecast value в int в перегруженном >> а также << операторы. Но опять же, что если T установлен в int_least64_t? Ну, мы могли бы Typecast value в int_64least_t вместо этого, но что если T установлен в uint_least64_t? Аналог, типографское оформление value в uint_least64_t создаст проблемы, если T установлен в int_least64_t, Не говоря уже о том, что реализации могут определять свои собственные, даже большие целые числа. В таком случае intmax_t а также uintmax_t может быть полезным, но только если T не установлен еще больший, пользовательский целочисленный тип.

Тут приходит с помощью одинарного + оператор. AFAIK это предназначено для преобразования целого числа символа в нормальное целое число, так что, например, cout относится к этому должным образом. И да, с оператором << это работает аккуратно: out << +i.value;

Тем не менее, делать то же самое с оператором >> гораздо страшнее Просто пишу in >> +i.value; создает неприятные ошибки компиляции. На самом деле, я не уверен, почему. Я должен использовать фиктивную переменную:

auto hlp = +i.value;
in >> hlp;
i.value = hlp;

Это безобразно Но что еще хуже, это может не проверить правильность диапазона. Если istream записывает в целочисленное значение, а затем в соответствии с http://www.cplusplus.com/reference/locale/num_get/get/ должен проверить, находится ли записанное значение в диапазоне. Если это не так, failbit установлен, и переменной, в которую была записана, даны стандартные определенные значения. Поэтому целочисленных переполнений не возникает. Здесь, однако, у меня нет гарантии, что auto hlp будет иметь тип точного размера типа i.value, Продолжая int_least8_t пример, hlp будет повышен до типа int который больше чем char; поэтому, кормление программы с вводом, например, 900 приведет к value устанавливается на -124,

Конечно, мы могли бы продолжить проверку диапазона, проверив hlp против numeric_limits<T>::lowest() а также numeric_limits<T>::max(), Однако это возможно только в том случае, если T настроен на фундаментальные типы. Это не удастся для пользовательских целочисленных типов, поскольку в соответствии с http://www.cplusplus.com/reference/limits/numeric_limits/ numeric_limits не может быть установлен для пользовательских типов.

Я согласен, что это очень сложная проблема. Но в этом суть - просто для упражнения я хотел бы быть как можно более перфекционистским.

0 ответов

Другие вопросы по тегам