【问题标题】:Why is there no std::stou?为什么没有 std::stou?
【发布时间】:2012-01-03 16:21:31
【问题描述】:

C++11 新增了一些字符串转换函数:

http://en.cppreference.com/w/cpp/string/basic_string/stoul

包括stoi(字符串到int),stol(字符串到long),stoll(字符串到long long),stoul(字符串到unsigned long),stoull(字符串到unsigned long long)。值得注意的是 stou(字符串转无符号)函数。是否有某些原因不需要它但所有其他的都需要?

相关:No "sto{short, unsigned short}" functions in C++11?

【问题讨论】:

  • 我的问题更接近于“仅使用 stoul 是否存在一些不明显的缺点”。显然这会与模板实例化混淆,但还有什么我没有考虑的吗?评论为什么它被遗漏会很好但次要。
  • @NicolBolas 我不明白为什么这不是建设性的。这是一个完全有效的问题,因为我看不出这种不一致的任何原因,并且答案可能会深入了解一些可能存在的有效但不是那么明显的原因。
  • @SethCarnegie 好吧,您的平台(也许是大多数平台)所做的只是无关紧要的,因为 unsigned long 只是没有 unsigned int
  • @SethCarnegie:在我的典型计算机上,unsigned long 是 64 位,unsigned int 是 32。它们是不同的类型,不能假定彼此相同。跨度>
  • @NicolBolas 就像说的那样,OP(和我)不知道它是推测性的,因为它可能有一个完美的正当理由深埋在 C++ 的语言内部。但既然你说这是投机,我想没有这样的理由。但同样,也许一个负责 C++11 的人仍然可以回答它。这不是“哇哇,那个该死的stou”问题,而是一个问题,询问这个明显不一致的可能明确的原因。如果您知道没有这样的原因,那么好吧,将其发布为答案。

标签: c++ string c++11 std


【解决方案1】:

最恰当的答案是 C 库没有对应的“strtou”,而 C++11 字符串函数都只是 C 库函数的薄薄的包装:std::sto* 函数镜像 @987654323 @,而std::to_string 函数使用sprintf


编辑:正如 KennyTM 所指出的,stoistol 都使用 strtol 作为底层转换函数,但仍然很神秘为什么虽然存在使用 strtoulstoul,但没有对应的stou.

【讨论】:

  • 你知道为什么 C++ 委员会决定采用这种 C-ish 方法吗?像boost::lexical_cast<>() 这样的东西似乎更像是一种 C++ 做事方式。
  • 这些实现细节真的是标准定义的吗?
  • @LightnessRacesinOrbit:对于sto*,C++11 21.5/1:效果:前两个函数调用strtol(str.c_str(), ptr, base),后三个函数调用strtoul(str.c_str(), ptr, base), strtoll(str.c_str(), ptr, base) 和 strtoull(str.c_str(), ptr, base)。
  • 不管 C++ 标准是否说“必须通过调用 ... 来实现”,因为 C++ 标准仍然有全局 as-if 规则:如果标准说 std::sto* 必须被实现为 C 库函数的包装器,并且有效的程序无法判断它们不是以不同方式秘密实现的,实现是有效的。
  • 完全跑题了,我认为不使用像 Boost/lexical_cast 这样的 iostream 的实际原因是纯粹的性能;我相信 iostreams 以相当大的优势输给 strtoul 等。
【解决方案2】:

我不知道为什么存在stoi 而不是stou,但stoul 和假设的stou 之间的唯一区别是检查结果是否在unsigned 的范围内:

unsigned stou(std::string const & str, size_t * idx = 0, int base = 10) {
    unsigned long result = std::stoul(str, idx, base);
    if (result > std::numeric_limits<unsigned>::max()) {
        throw std::out_of_range("stou");
    }
    return result;
}

(同样,stoi 也与stol 相似,只是范围检查不同;但既然已经存在,就无需担心具体如何实现。)

【讨论】:

  • stoistolstolstoll 之间的区别也只是范围检查。
  • @Hossein:在stoistol 之间,是的。但是stolstoll 的区别不仅在于范围检查,它们调用的库函数也不同。
【解决方案3】:
unsigned long ulval = std::stoul(buf);
unsigned long mask = ~0xffffffffl;
unsigned int uival;
if( (ulval & mask) == 0 )
    uival = (unsigned int)ulval;
else {
    ...range error...
}

使用掩码以掩码中表示的预期值大小(以位为单位)执行此操作,这将使其适用于 64 位长整数与 32 位整数,也适用于 32 位长整数与 32 位整数。

在 64 位 long 的情况下,~0xffffffffl 将变为 0xffffffff00000000,因此将查看是否设置了前 32 位。对于 32 位长,它 ~0xffffffffl 变为 0x00000000 并且掩码检查将始终为零。

【讨论】:

  • 如果buf"0",这将假定发生了范围错误。
猜你喜欢
  • 2017-01-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-09
  • 2015-03-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多