微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

c – 将字符串转换为整数类型T,检查溢出

目标是一个函数,给定包含数字的字符串和整数类型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的情况.这已经修复了.

原文地址:https://www.jb51.cc/c/118906.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐