stringstream 运算符>>无法在调试中分配数字

stringstream operator>> fails to assign a number in debug

提问人:GiaMat45 提问时间:11/3/2022 最后编辑:Remy LebeauGiaMat45 更新时间:11/4/2022 访问量:75

问:

我有一个简单的函数,给定一个字符串,如果它是一个数字,则返回“true”并覆盖引用输入。strnum

template <typename T>
bool toNumber(string str, T& num)
{
    bool bRet = false;
    if(str.length() > 0U)
    {
        if (str == "0")
        {
            num = static_cast<T>(0);
            bRet = true;
        }
        else
        {
            std::stringstream ss;
            ss << str;
            ss >> num;    // if str is not a number op>> it will assign 0 to num
            if (num == static_cast<T>(0)) 
            {
                bRet = false;
            }
            else
            {
                bRet = true;
            }
        }
    }
    else
    {
        bRet = false;
    }
    return bRet;
}

所以我希望:

int x, y;
toNumber("90", x); // return true and x is 90
toNumber("New York", y); // return false and let y unasigned.

在我的机器上,debug 和 release 配置都工作正常,但在服务器上,只有使用调试配置,在像“ss >> num”这样的调用中无法识别这是一个字符串。toNumber("New York", y)str

我检查了项目配置,但它们对于两台机器都是相同的(服务器是我本地 vs-2015 项目的 svn-checkout)。

我真的不知道如何解决这个问题。谁能帮我解决这个问题?

C 视觉-C++ IOstream 字符串流 istream

评论


答:

0赞 n. m. could be an AI 11/3/2022 #1

if (num == static_cast<T>(0))

坏主意。要知道是否失败,请检查流的状态。operator>>

if (ss >> num) { ...

一旦你有了这个检查,(完全不正确的)部分

    if (str == "0")
    {
        num = static_cast<T>(0);
        bRet = true;
    }

变得多余,并且

if(str.length() > 0U)

也变得多余,然后整个事情简化为一两行。

评论

0赞 GiaMat45 11/4/2022
谢谢你的提示。受此启发,我将 if 语句从 改为 to,它有效!if (num == static_cast<T>(0))if (ss.fail())
1赞 Remy Lebeau 11/4/2022
@GiaMat45 你真的应该用而不是if (ss >> num)ss >> num; if (ss.fail())
0赞 GiaMat45 11/4/2022
@RemyLebeau是的,我同意你的看法,我将直接使用 if。谢谢!>>
1赞 Marek R 11/4/2022 #2

你的代码太复杂了,你可以把它简化为:

template <typename T>
bool toNumber(std::string str, T& num)
{
    return !!(std::istringstream { std::move(str) } >> num);
}

https://godbolt.org/z/Pq5xGdof5

好的,我错过了您希望在失败时避免零分配(默认情况的作用):

template <typename T>
bool toNumber(std::string str, T& num)
{
    T tmp;
    std::istringstream stream{ std::move(str) };
    if (stream >> tmp) {
        num = tmp;
    }
    return !!stream;
}

https://godbolt.org/z/nErqn3YYG

评论

0赞 Remy Lebeau 11/4/2022
OP 的问题中没有任何内容表明在返回时应保持未分配状态。这样做只会引入一个不必要的逻辑分支。举个例子,OP 的原始代码如果不为空或流失败,则执行零分配。numfalsenumstr"0"
0赞 Marek R 11/4/2022
在代码注释中表示: 和 .不是很直接,但仍然如此。当你想到为什么他的代码如此复杂时,这一定是一个根本原因(例如:必须是那个)。// return false and let y unasigned.// if str is not a number op>> it will assign 0 to numif (str == "0")
0赞 Remy Lebeau 11/4/2022
OP 代码的编写方式具有误导性,实际上更像是 since is true。 仅当为空时才未分配,但如果失败,则将分配。行为不是很一致。评论真的应该更像return false and let y unasignedreturn false and y may or may not be left unasignedif str is not a number op>> it will assign 0 to numystr0stringstreamreturn false and ignore y
5赞 Remy Lebeau 11/4/2022 #3

检查输出的数字的值是错误的方法。您应该检查 的失败状态,例如:operator>>stringstream

template <typename T>
bool toNumber(string str, T& num)
{
    bool bRet = false;
    if (str.length() > 0U)
    {
        if (str == "0")
        {
            num = static_cast<T>(0);
            bRet = true;
        }
        else
        {
            std::stringstream ss;
            ss << str;
            if (ss >> num) // <--
            {
                bRet = true;
            }
            else
            {
                bRet = false;
            }
        }
    }
    else
    {
        bRet = false;
    }
    return bRet;
}

operator>>返回对输入流的引用,并且该流在布尔上下文中可隐式转换为,如语句,其中表示流处于良好状态,表示流处于失败状态。booliftruefalse

在这种情况下,您可以通过摆脱冗余分配来进一步大大简化函数,并且冗余输入检查已经为您处理,例如:bRetstringstream

template <typename T>
bool toNumber(const string &str, T& num)
{
    std::istringstream ss(str);
    return static_cast<bool>(ss >> num);
    // or:
    // return !!(ss >> num);
}

在线演示

评论

0赞 GiaMat45 11/4/2022
感谢您的提示,但没有返回布尔值,然后编译器抛出此错误return (ss >> num)'return': cannot convert from 'std::basic_istream<char,std::char_traits<char>>' to 'bool'
0赞 GiaMat45 11/4/2022
好的,现在演员阵容很好用!我将采用这个非常紧凑的版本。太棒了!