Гарантировано ли, что std::char_traits <char> ::to_int_type(c) == static_cast <int> (c)?

Вопрос Как правильно использовать возвращаемое значение из <tcode id="238412"></tcode> и <tcode id="238413"></tcode>? заставил меня задуматься, гарантировано ли это

      std::char_traits<char>::to_int_type(c) == static_cast<int>(c)

для всех допустимых значений.


Это встречается во многих местах. Например, istream::peek звонки streambuf::sgetc, который использует to_int_type преобразовать значение в int_type. Это действительно означает, что следующий символ \n?


Вот мой анализ. Соберем кусочки из [char.traits.require] и [char.traits.specializations.char] :

  1. Для каждого значения to_char_type(e) возвращается

    • , если для некоторых;

    • некоторое неуказанное значение в противном случае.

  2. Для каждой пары значений и, eq_­int_­type(e, f) возвращается

    • , если и для некоторых и;

    • true, если и;

    • false, если e == eof() xor f == eof();

    • не указано иное.

  3. eof() возвращает такое значение, что !eq_int_type(e, to_int_type(c)) для всех .

  4. если только (unsigned char) c == (unsigned char) d.

Теперь рассмотрим эту гипотетическую реализацию: (синтаксически упрощено)

      //          char: [-128, 127]
// unsigned char: [0, 255]
//           int: [-2^31, 2^31-1]

#define EOF INT_MIN

char to_char_type(int e) {
    return char(e - 1);
}

int to_int_type(char c) {
    return int(c) + 1;
}

bool eq(char c, char d) {
    return c == d;
}

bool eq_int_type(int c, int d) {
    return c == d;
}

int eof() {
    return EOF;
}

Обратите внимание, что

  • (свойство 1) преобразование из в сохраняет ценность;

  • (свойство 2) преобразование из в unsigned char биективен.

Теперь проверим требования:

  1. Для каждого значения, если ​eq_­int_­type(e, ​to_­int_­type(c)) для некоторых тогда e == int(c) + 1. Следовательно, to_char_type(e) == char(int(c)) == c.

  2. Для каждой пары int значения e и f, если e == to_int_type(c) и f == to_int_type(d) для некоторых, а затем eq_int_type(e, f) если только int(c) + 1 == int(d) + 1 если только c == d(по свойству 1). Случаи EOF также легко поддаются проверке.

  3. Для каждого значения int(c) >= -128, так int(c) + 1 != EOF. Следовательно, !eq_int_type(eof(), to_int_type(c)).

  4. Для каждой пары char значения c и d, eq(c, d) если только (unsigned char) c == (unsigned char d) (по свойству 2).

Означает ли это, что эта реализация соответствует требованиям, и поэтому std::cin.peek() == '\n'не делает то, что должен делать? Я что-то пропустил в своем анализе?

1 ответ

Означает ли это, что эта реализация соответствует требованиям, и поэтому std ::cin.peek() == '\n' не выполняет того, что должен делать?

Я согласен с твоим анализом. Это не гарантировано.

Похоже, вам придется использовать eq_­int_­type(std::cin.peek(), ​to_­int_­type('\n')) чтобы гарантировать правильный результат.


PS Ваш ​to_­char_­type(EOF) имеет неопределенное поведение из-за подписанного переполнения в INT_MIN - 1. Конечно, в этом случае значение не указано, но у вас по-прежнему не может быть UB. Это было бы верно:

      char to_char_type(int e) {
    return e == EOF
         ? 0 // doesn't matter
         : char(e - 1);
}

to_int_type будет иметь UB в системах, где int и char имеют одинаковый размер в случае c == INT_MAX, но вы исключили системы с гипотетическими размерами.

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