125

C++11 added some new string conversion functions:

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

It includes stoi (string to int), stol (string to long), stoll (string to long long), stoul (string to unsigned long), stoull (string to unsigned long long). Notable in its absence is a stou (string to unsigned) function. Is there some reason it is not needed but all of the others are?

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

Community
  • 1
  • 1
David Stone
  • 26,872
  • 14
  • 68
  • 84
  • Not constructive, for the same reason that the other question is not constructive. – Nicol Bolas Jan 03 '12 at 16:26
  • 7
    My question was intended to be more along the lines of "is there some non-obvious drawback of just using stoul". Obviously that will mess with template instantiation, but is there anything else that I'm not considering? Comments on why it was left out would be nice but secondary. – David Stone Jan 03 '12 at 16:30
  • 19
    @NicolBolas I cannot see why this is not constructive. It is a perfectly valid question as I cannot see any reason for this inconsistency and anwers may give insights into some possibly existing valid but not that obvious reason for it. – Christian Rau Jan 03 '12 at 16:33
  • @DavidStone on my compiler (and my computer is a typical one), `unsigned long` is the same size and has the same storage capacity as `unsigned int` – Seth Carnegie Jan 03 '12 at 16:33
  • 6
    @SethCarnegie Well, what your platform (and maybe the majority of platforms) does is just irrelevant, because an `unsigned long` just is no `unsigned int`. – Christian Rau Jan 03 '12 at 16:35
  • 6
    @SethCarnegie: on my typical computer, `unsigned long` is 64 bits, and `unsigned int` 32. They are different types, and can't be assumed to be the same as each other. – Mike Seymour Jan 03 '12 at 16:35
  • @ChristianRau: The reason it's not constructive is for the same reason the other question was closed: it would be purely speculative. – Nicol Bolas Jan 03 '12 at 16:37
  • 3
    @NicolBolas Like said, the OP (and me) doesn't know it is speculative, as there could just be a perfect valid reason for it burried deep in the language internals of C++. But since you say it's speculative I guess there is no such reason. But again, maybe a C++11-responsible person can still answer it. This is no "Wah wah, where is that damn `stou`"-question, but a question asking for a possibly definite reason for this obvious inconsistency. If you **know** there is no such reason, then well, post it as an answer. – Christian Rau Jan 03 '12 at 16:39
  • 3
    Oi. Hurry up and close this so I can vote to re-open. – Lightness Races in Orbit Jan 03 '12 at 17:11
  • @Nicol: Aren't the reasoning behind committee decisions accessible to the public? It doesn't seem to me that this question can only have a speculative answer. – Tanz87 Oct 28 '17 at 16:17

3 Answers3

38

The most pat answer would be that the C library has no corresponding “strtou”, and the C++11 string functions are all just thinly veiled wrappers around the C library functions: The std::sto* functions mirror strto*, and the std::to_string functions use sprintf.


Edit: As KennyTM points out, both stoi and stol use strtol as the underlying conversion function, but it is still mysterious why while there exists stoul that uses strtoul, there is no corresponding stou.

Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • 16
    Do you know why the C++ Committee decided to go for such a C-ish approach? Something like `boost::lexical_cast<>()` seems like a more C++ way of doing things. – Paul Manta Jan 03 '12 at 17:27
  • 2
    Are these implementation details really standard-defined? – Lightness Races in Orbit Jan 03 '12 at 17:32
  • @LightnessRacesinOrbit: Yes, they are. – Mike Seymour Jan 03 '12 at 17:38
  • @MikeSeymour: Perhaps you could cite chapter and verse. It seems unlikely to me that the standard says "`std::to_string` must be implemented with `sprintf`". 21.5/7 merely states an "as-if" rule for the behaviour of the function. – Lightness Races in Orbit Jan 03 '12 at 17:52
  • 4
    @LightnessRacesinOrbit: For `sto*`, C++11 21.5/1: Effects: the first two functions call strtol(str.c_str(), ptr, base), and the last three functions call strtoul(str.c_str(), ptr, base), strtoll(str.c_str(), ptr, base), and strtoull(str.c_str(), ptr, base), respectively. – Mike Seymour Jan 03 '12 at 17:53
  • @LightnessRacesinOrbit: But you're correct that `to_string` just says "the value of its argument that would be generated by calling `sprintf`". – Mike Seymour Jan 03 '12 at 17:56
  • 13
    It doesn't matter whether the C++ standard says "must be implemented by calling ...", because the C++ standard still has the global as-if rule: if the standard says `std::sto*` must be implemented as wrappers for the C library functions, and a valid program cannot tell that they aren't secretly implemented differently, the implementation is valid. –  Jan 03 '12 at 18:12
  • 3
    Completely off-topic, I think the practical reasons for not using iostreams like Boost/lexical_cast does is sheer performance; I believe iostreams lose out against strtoul etc. by a considerable margin. – Kerrek SB Jan 03 '12 at 18:31
  • 1
    This doesn't explain why `stoi` exists. – kennytm Jan 04 '12 at 13:10
  • @KennyTM: Interesting. Actually it says that `stoi` and `stol` both call `strtol`. – Kerrek SB Jan 04 '12 at 14:33
  • 3
    Well, I believe `boost::lexical_cast` is specialized for maximum performance for various types, and thus almost always has better performance than other methods: http://www.boost.org/doc/libs/release/doc/html/boost_lexical_cast/performance.html – David Stone Aug 05 '12 at 14:46
  • @PaulManta: Simple. `strto...()` and `std::sto...()` (optionally) report the position of the first input character *not* parsed as part of the number. Very useful information if you are parsing potentially malformed input. `boost::lexical_cast<>()` doesn't. – DevSolar Feb 26 '16 at 14:19
27

I've no idea why stoi exists but not stou, but the only difference between stoul and a hypothetical stou would be a check that the result is in the range of 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;
}

(Likewise, stoi is also similar to stol, just with a different range check; but since it already exists, there's no need to worry about exactly how to implement it.)

Mike Seymour
  • 249,747
  • 28
  • 448
  • 644
  • The difference between `stoi` and `stol`, or `stol` and `stoll` is also only a range check. – Hossein Jan 03 '12 at 17:30
  • 1
    @Hossein: Between `stoi` and `stol`, yes. But `stol` and `stoll` do not differ only in range check, they call different library functions. – Ben Voigt Jul 05 '14 at 20:59
0
unsigned long ulval = std::stoul(buf);
unsigned long mask = ~0xffffffffl;
unsigned int uival;
if( (ulval & mask) == 0 )
    uival = (unsigned int)ulval;
else {
    ...range error...
}

Using masks to do this with the expected value size in bits expressed in the mask, will make this work for 64-bit longs vs 32-bit ints, but also for 32-bit longs vs 32-bit ints.

In the case of 64-bit longs, ~0xffffffffl will become 0xffffffff00000000 and will thus see if any of the top 32 bits are set. With 32-bit longs, it ~0xffffffffl becomes 0x00000000 and the mask check will always be zero.