std::stoiでは余分の文字が入ってる場合でも変換できます、例えばstd::stoi("123x1")は123を返します。
ここでより安全なstoiを作ってみました。
ソースコード
template <class T>
inline void stoi_s(const std::string& str, T& result, int base = 10) {
char* end = nullptr;
errno = 0;
long long i = ::strtoll(str.c_str(), &end, base);
if (end != (str.c_str() + str.size()) || str.size() <= 0 || errno != 0) {
throw std::invalid_argument("stoi_s");
}
if (i < 0 && !std::numeric_limits<T>::is_signed) {
// if T is unsigned, i will convert to unsigned before compare to result_test
// make sure i is not negative here
throw std::out_of_range("stoi_s");
}
T result_test = static_cast<T>(i);
if (result_test != i) {
throw std::out_of_range("stoi_s");
}
result = result_test;
}
テスト
template <class TException, class TFunction>
bool exception_catched(TFunction function) {
try {
function();
} catch(TException&) {
return true;
}
return false;
}
void test() {
uint8_t a = 0;
int32_t b = 0;
uint64_t c = 0;
stoi_s("100", a);
assert(a == 100);
stoi_s("-100", b);
assert(b == -100);
stoi_s("-0x80000000", b, 16);
assert(b == -0x80000000);
assert(exception_catched<std::invalid_argument>([&] { stoi_s("asd", a); }));
assert(exception_catched<std::invalid_argument>([&] { stoi_s("1asd", a); }));
assert(exception_catched<std::out_of_range>([&] { stoi_s("-1", a); }));
assert(exception_catched<std::out_of_range>([&] { stoi_s("300", a); }));
assert(exception_catched<std::out_of_range>([&] { stoi_s("-0x80000001", b, 16); }));
assert(exception_catched<std::out_of_range>([&] { stoi_s("-1", c); }));
assert(exception_catched<std::invalid_argument>([&] {
stoi_s("0x8000000000000000", c, 16);
}));
}
manページ
http://linuxjm.sourceforge.jp/html/LDP_man-pages/man3/strtoll.3.html