Учитывая строку, которая должна представлять число, я хотел бы поместить ее в функцию преобразования, которая будет предоставлять уведомление, если все Строка не преобразована.
Для ввода: "12"
:
istringstream::operator>>
выходы 12atoi
выходы 12stoi
выходы 12Для ввода "1X"
Я хотел бы получить ответ об ошибке, но я получаю:
istringstream::operator>>
выходы 1atoi
выходы 1stoi
выходы 1Для ввода "X2"
:
istringstream::operator>>
выводит 0 и устанавливает флаг ошибкиatoi
выходы 0stoi
выдает ошибкуЕсть ли способ спровоцировать ошибки поведения на входе "1X"
?
Для данного 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";
}
[Живой пример]
В качестве альтернативы вы можете использовать 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>>
, Примечание: я не совсем уверен, достаточно ли условия, но с моим тестированием это казалось. По какой-то причине поток получит маркировку сбоев, если он проанализирован до конца.