目标是一个函数,给定包含数字的字符串和整数类型T,如果值适合没有溢出的类型,则返回成功转换值,否则返回失败.
使用std :: istringstream从字符串中读取数字适用于某些情况:
template<typename T> std::pair<bool,T> decode(std::string s) { T value; std::istringstream iss(s); iss >> std::dec >> value; return std::pair<bool,T>(!iss.fail(),value); } template<typename T> void testDecode(std::string s) { std::pair<bool,T> result = decode<T>(s); if (result.first) std::cout << +result.second; else std::cout << "ERROR"; std::cout << std::endl; } int main() { testDecode<int32_t>("12"); // 12 testDecode<int16_t>("1000000"); // ERROR testDecode<int16_t>("65535"); // ERROR return 0; }
但是,它对8位类型失败(因为它们被视为chars):
testDecode<uint8_t>("12"); // 49 !
负数也被错误地接受并解析为无符号类型:
testDecode<uint16_t>("-42"); // 65494 !
这种功能由例如提供. 07年在D和str::parse
在Rust.什么是C等价物?
解决方法
您的解决方案似乎很好但是,如果您想要更好的编译时优化,则应考虑进行模板特化.在显示的代码中,您根据类型进行分支.然而,这可能被编译到代码中,而不是在编译时(已经可能的地方)解析.此外,如果您想根据类型添加其他检查,该功能很快就会变得混乱.
我编写了我自己的转换代码版本,除了你的版本之外,还会检查是否为整数类型提供了科学记数法:
#include <type_traits> #include <utility> #include <string> #include <limits> #include <algorithm> template <typename T> auto to_T(const std::string &s) -> std::enable_if_t<std::is_floating_point<T>::value,std::pair<bool,T>> { return std::pair<bool,T>{true,T(std::stold(s))}; //read the string into the biggest floating point possible,and do a narrowing conversion } template <typename T> auto to_T(const std::string &s) -> std::enable_if_t<!std::is_floating_point<T>::value && std::is_signed<T>::value,T>> { return ((long long)(std::numeric_limits<T>::min()) <= std::stoll(s) && //does the integer in the string fit into the types data range? std::stoll(s) <= (long long)(std::numeric_limits<T>::max())) ? std::pair<bool,T(std::stoll(s))} : std::pair<bool,T>{false,0}; //if yes,read the string into the biggest possible integer,and do a narrowing conversion } template <typename T> auto to_T(const std::string &s) -> std::enable_if_t<!std::is_floating_point<T>::value && std::is_unsigned<T>::value,T>> { return ((unsigned long long)(std::numeric_limits<T>::min()) <= std::stoull(s) && //does the integer in the string fit into the types data range? std::stoull(s) <= (unsigned long long)(std::numeric_limits<T>::max())) ? std::pair<bool,T(std::stoull(s))} : std::pair<bool,and do a narrowing conversion } template <typename T> auto decode(const std::string &s) -> std::enable_if_t<std::is_floating_point<T>::value,T>> { return s.empty() ? //is the string empty? std::pair<bool,0} : to_T<T>(s); //if not,convert the string to a floating point number } template <typename T> auto decode(const std::string &s) -> std::enable_if_t<!std::is_floating_point<T>::value && std::is_signed<T>::value,T>> { return (s.empty() || //is the string empty? std::find(std::begin(s),std::end(s),'.') != std::end(s) || //or does it not fit the integer format? std::find(std::begin(s),',') != std::end(s) || std::find(std::begin(s),'e') != std::end(s) || std::find(std::begin(s),'E') != std::end(s)) ? std::pair<bool,0} : to_T<T>(s); //if not,convert the string to a signed integer value } template <typename T> auto decode(const std::string &s) -> std::enable_if_t<!std::is_floating_point<T>::value && std::is_unsigned<T>::value,'E') != std::end(s) || std::find(std::begin(s),'-') != std::end(s)) ? //or does it have a sign? std::pair<bool,convert the string to an unsigned integer value }
这仍然需要在平台之间进行一些移植,因为std :: stold,std :: stoll或std :: stoull可能不可用.但除此之外,它应该独立于平台类型实现.
编辑:
我忘了一个解码不应该读取数字但是返回0的情况.这已经修复了.