Принуждение строки к функции int потреблять всю строку

Учитывая строку, которая должна представлять число, я хотел бы поместить ее в функцию преобразования, которая будет предоставлять уведомление, если все Строка не преобразована.

Для ввода: "12":

  • istringstream::operator>> выходы 12
  • atoi выходы 12
  • stoi выходы 12

Для ввода "1X" Я хотел бы получить ответ об ошибке, но я получаю:

  • istringstream::operator>> выходы 1
  • atoi выходы 1
  • stoi выходы 1

Для ввода "X2":

  • istringstream::operator>> выводит 0 и устанавливает флаг ошибки
  • atoi выходы 0
  • stoi выдает ошибку
[Живой пример]

Есть ли способ спровоцировать ошибки поведения на входе "1X"?

6

Решение

Для данного string str Есть несколько способов сделать это, каждый из которых имеет свои преимущества и недостатки.

Как предложено Вот strtolВыходной параметр можно использовать для получения количества прочитанных символов. strtol на самом деле возвращает long не int так что актерский состав происходит по возвращении.

char* size;
const int num = strtol(i.c_str(), &size, 10);

if(distance(i.c_str(), const_cast<const char*>(size)) == i.size()) {
cout << "strtol: " << num << endl;
} else {
cout << "strtol: error\n";
}

Обратите внимание, что это использует i.c_str() ссылаться на одну и ту же строку. c_str Возвращает указатель на базовый массив, служащий хранилищем символов, а не временный, если у вас есть C ++ 11:

c_str() а также data() выполнять ту же функцию

Также обратите внимание, что указатель возвращается c_str будет действительным между strtol а также distance звонки, если:

  • Проходяconst ссылка на string в любую стандартную библиотечную функцию
  • Вызов неconst функции-члены на string, исключая operator[], at(), front(), back(), begin(), rbegin(), end() а также rend()

Если вы нарушите любой из этих случаев, вам нужно будет сделать временную копию iв основе const char* и выполнить тест на этом.

sscanf можешь использовать %n вернуть количество прочитанных символов, которое может быть более интуитивно понятным, чем сравнение указателей. Если база важна, sscanf не может быть хорошим выбором. В отличие от strtol а также stoi которые поддерживают базы 2 — 36, sscanf предоставляет спецификаторы только для восьмеричного числа (%o), десятичный (%d) и шестнадцатеричный (%x).

size_t size;
int num;

if(sscanf(i.c_str(), "%d%n", &num, &size) == 1 && size == i.size()) {
cout << "sscanf: " << num << endl;
} else {
cout << "sscanf: error\n";
}

Как предложено Вот stoiвыходной параметр работает как sscanf«s %n возвращая количество прочитанных символов. В соответствии с C ++ это занимает string и в отличие от реализаций C выше stoi бросает invalid_argument если первый непробельный символ не считается цифрой для текущей базы, и это, к сожалению, означает, что в отличие от реализаций C это должно проверять наличие ошибок в обоих try а также catch блоки.

try {
size_t size;
const auto num = stoi(i, &size);

if(size == i.size()) {
cout << "stoi: " << num << endl;
} else {
throw invalid_argument("invalid stoi argument");
}
} catch(const invalid_argument& /*e*/) {
cout << "stoi: error\n";
}
[Живой пример]
3

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

В качестве альтернативы вы можете использовать std::istringstream как вы упоминали, но убедитесь, что он проанализирован до конца потока. Предполагая, что у вас есть постоянная ссылка, вы можете сделать что-то вроде следующего

T parse(const std::string& input) {
std::istringstream iss(input);
T result;
iss >> result;
if (iss.eof() || iss.tellg() == int(input.size())) {
return result;
} else {
throw std::invalid_argument("Couldn't parse entire string");
}
}

Преимущество этого подхода заключается в том, что вы анализируете все, что перегружает operator>>, Примечание: я не совсем уверен, достаточно ли условия, но с моим тестированием это казалось. По какой-то причине поток получит маркировку сбоев, если он проанализирован до конца.

1

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