Overloading of the family of numeric conversion functions std::stoXXX

188 views
Skip to first unread message

Vlad from Moscow

unread,
Oct 2, 2015, 11:27:01 AM10/2/15
to ISO C++ Standard - Future Proposals
The C++ Standard includes a family of conversion functions like std::stoi, std::stol, std::stoul and other similar functions.

They allow to convert a string to some arithmetic type.

However it is not always convinient to use them when you are going to apply the function to a string starting from some non-zero position.

In this case you need to use either member function substr to get the desired substring. or to use another member function c_str that to apply the corresponding C function instead of the C++ function.

So I think you have already understood that I want to suggest overloading functions that have one more parameter that specifies a position in the string.

For example function stoi can now  look like

int stoi(const string& str, size_t* idx = 0, int base = 10);

int stoi(const string& str, std::string::size_type pos, size_t* idx = 0, int base = 10);

What do you think about this?

Jared Grubb

unread,
Oct 2, 2015, 11:35:36 AM10/2/15
to ISO C++ Standard - Future Proposals
The string_view proposal adds overloads for these functions for string_view, which would let you have everything you are asking for. (http://open-std.org/jtc1/sc22/wg21/docs/papers/2013/n3685.html#string.conversions)

Jared

Vlad from Moscow

unread,
Oct 2, 2015, 11:52:04 AM10/2/15
to ISO C++ Standard - Future Proposals
In my opinion using string_view in this case makes things even more harder

Why does someone need to introduce one more entity that just to apply for example std::stoi to a string?

It does not make a great sense.

I think that the functions should be overloaded as I am suggesting irrespective of whether the string_view will be adopted or wil not.

Vlad from Moscow

unread,
Oct 2, 2015, 12:00:11 PM10/2/15
to ISO C++ Standard - Future Proposals
By the way I advice to add in the description of the view_string the functions I am proposing.:)

On Friday, October 2, 2015 at 6:35:36 PM UTC+3, Jared Grubb wrote:

Matthew Woehlke

unread,
Oct 2, 2015, 2:07:31 PM10/2/15
to std-pr...@isocpp.org
On 2015-10-02 11:27, Vlad from Moscow wrote:
> The C++ Standard includes a family of conversion functions like std::stoi,
> std::stol, std::stoul and other similar functions.
>
> They allow to convert a string to some arithmetic type.
>
> However it is not always convinient to use them when you are going to apply
> the function to a string starting from some non-zero position.
>
> [...proposing...]
>
> int stoi(const string& str, size_t* idx = 0, int base = 10);
>
> int stoi(const string& str, std::string::size_type pos, size_t* idx = 0,
> int base = 10);
>
> What do you think about this?

I think that 'stoi(str.view(pos));' is no worse than 'stoi(str, pos)',
is more descriptive, and is more generally useful :-). (I would indeed
like methods to get a partial string_view directly from a string. Too
bad size_type is unsigned, or we could get the full range of Qt's
substring methods / Python's slicing, including far-relative offsets.
OTOH, maybe we can have overloads that take signed types; using them
would limit code to working with strings that are only half of
numeric_limits<size_type>::max in length, but how often are they really
larger?)

--
Matthew

Vlad from Moscow

unread,
Oct 2, 2015, 2:41:09 PM10/2/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
I can not agree. in my opinion stoi(str.view(pos)) is much worse than the straightforward  stoi(str, pos).

stoi(str.view(pos)) only confuses readres because str.vew has an additional semantic that is not required in this case. It only arises questions. str.view is something else apart from str itself.

This expression stoi(str, pos). is more clear .And moreover relative to the argument list it is similar to calls of other member functions of the class   We have a string and we have a position in the string. Why do we need something else?!

On the other hand  this expression str.view(pos) looks like we are going to call some method for the argument pos. That is the whole expression
stoi(str.view(pos))  looks as a two step operation. At first we call some method with argument pos and only then we call the function itself.  

Bengt Gustafsson

unread,
Oct 2, 2015, 3:34:30 PM10/2/15
to ISO C++ Standard - Future Proposals
I think the main problem is that you can't detect how much of the input string was consumed. There are older proposals trying to solve this as well as handling parsing errors.

Vlad from Moscow

unread,
Oct 2, 2015, 3:55:54 PM10/2/15
to ISO C++ Standard - Future Proposals
I am sorry I have not understood what exactly you mean. What is the difference between these two functions

int stoi(const string& str, size_t* idx = 0, int base = 10);

int stoi(const string& str, std::string::size_type pos, size_t* idx = 0, int base = 10);

that creates the problem?

Nicol Bolas

unread,
Oct 2, 2015, 4:00:04 PM10/2/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Friday, October 2, 2015 at 2:41:09 PM UTC-4, Vlad from Moscow wrote:
I can not agree. in my opinion stoi(str.view(pos)) is much worse than the straightforward  stoi(str, pos).

Well, here's the thing. There are dozens of ways of extracting a substring from a string. And for every one of them, some user, somewhere, will want `stoi` to use their pet version of that extraction.

What makes your "string + interger" extraction better? Who's to say that everyone thinks that "string + integer" automatically means "offset from the front of the string"?

By using string_view, we eliminate this problem. Or rather, we foist it on the user, rather than on `stoi`'s interface. So there's no need to argue over the receiving function; the argument is over std::string's interface.
 
stoi(str.view(pos)) only confuses readres because str.vew has an additional semantic that is not required in this case. It only arises questions. str.view is something else apart from str itself.

This expression stoi(str, pos). is more clear .

... is it? OK, what does it mean? Without looking back through the thread, I had no idea. Granted, I also didn't know what str.view(pos) means either. But I'd know what str.first(count) or str.remove_first(count) would return.
 
And moreover relative to the argument list it is similar to calls of other member functions of the class   We have a string and we have a position in the string. Why do we need something else?!

On the other hand  this expression str.view(pos) looks like we are going to call some method for the argument pos.

That's because you are.
 
That is the whole expression
stoi(str.view(pos))  looks as a two step operation.

That's because it is.
 
At first we call some method with argument pos and only then we call the function itself.

That's because you will.

Your problem is that you're trying to conflate two operations: extracting a substring and converting a (sub) string into an integer. That's wrong..

Matthew Woehlke

unread,
Oct 2, 2015, 4:18:06 PM10/2/15
to std-pr...@isocpp.org
On 2015-10-02 16:00, Nicol Bolas wrote:
> On Friday, October 2, 2015 at 2:41:09 PM UTC-4, Vlad from Moscow wrote:
>> I can not agree. in my opinion stoi(str.view(pos)) is much worse than the
>> straightforward stoi(str, pos).
>
> Well, here's the thing. There are dozens of ways of extracting a substring
> from a string. And for every one of them, some user, *somewhere*, will want
> `stoi` to use their pet version of that extraction.
>
> What makes your "string + interger" extraction better? Who's to say that
> everyone thinks that "string + integer" automatically means "offset from
> the front of the string"?
>
> By using string_view, we eliminate this problem. Or rather, we foist it on
> the *user*, rather than on `stoi`'s interface. So there's no need to argue
> over the receiving function; the argument is over std::string's interface.

Exactly (thanks, Nicol, for that great explanation). This is separation
of concerns, which is a good thing (see also again Nicol's comment at
the bottom). Keeping the interfaces lightweight but providing more of
them that can be strung together (a.k.a. the UNIX philosophy) results in
a better, more flexible overall system.

Besides, it's less clear from 'stoi(string, size_t)' what the size_t
parameter is supposed to mean. It's more obvious in e.g.
QString::mid(int, int) that the first parameter is the offset into the
string. (Less so with string::view, due to the name, but still more than
in stoi.)

> Granted, I also didn't know what str.view(pos) means either.

Sure. I like that it's concise, but substr_view, or mid_view, or even
just midv might be better. (Another reason is that 'view' can be like
QString::mid / string::substr, and then we could potentially add lview
and rview like QString::{left,right}. However, that's OT for this thread.)

> But I'd know what str.first(count) or str.remove_first(count) would return.

(Also OT, but personally I prefer take_first... "remove" -> void, "take"
-> what was taken.)

>> On the other hand this expression str.view(pos) looks like we are going
>> to call some method for the argument pos.
>
> That's because you are.

Exactly. You are obtaining a partial view of the string and then
operating on that. Yes, in a strict technical sense, it may be
infinitesimally more efficient for stoi to just skip some characters,
but separating the operations is a better conceptual match.

> Your problem is that you're trying to conflate two operations: extracting a
> substring and converting a (sub) string into an integer. That's wrong..

Yup :-).

--
Matthew

Vlad from Moscow

unread,
Oct 3, 2015, 4:35:08 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi. I would indeed do these two operations if I do not suggest the overloaded functions.

By the way it is you who is trying to do two operations.:) And it is more than evident from your code

stoi(str.view(pos))

So you are truing to hand over your own problems to me. No thank you. 

I do not understand why do I need a truck that to do just a step?:)

Vlad from Moscow

unread,
Oct 3, 2015, 5:02:04 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
And here is a simple demonstrative program

#include <iostream>
#include <string>

int main()
{
    std::string s( "Here is number 100 you need to extract" );
   
    std::cout << stoul( s, s.find_first_of( "0123456789" ) ) << std::endl;   
}   
Its output is

100

It is very clear code with very clear semantic that does not create some unnecessary entities.

Each piece of the code also is very clear and does not arise a question.

And it does not require a truck as you suggest.:)
.


On Friday, October 2, 2015 at 11:00:04 PM UTC+3, Nicol Bolas wrote:

Bengt Gustafsson

unread,
Oct 3, 2015, 6:50:24 AM10/3/15
to ISO C++ Standard - Future Proposals
Oh, I thought you meant to replace the old idx with a in-parameter pos. For easiest use I think an inout reference position would be best:

stoi(const string& str, size_t& pos, int base = 10);

You could argue that pos should be a pointer, but that train has sailed due to the current signature.

I would prefer string_view& with an overload for const string_view& or string_view&& where you couldn't get the consumption back, but I think that string_view is not going to be mutable, and in that case I would prefer a size_t&

stoi(string_view& str, int base = 10);    // Changes str's start point to reflect consumption
stoi(const string_view& str, int base = 10); // Does not change reveal consumption.

Vlad from Moscow

unread,
Oct 3, 2015, 7:10:12 AM10/3/15
to ISO C++ Standard - Future Proposals
I am suggesting a minor change of the original funcions. That is all other parameters are the same. only overloaded functions are added that have one additional parameter: position in a string.

Nicol Bolas

unread,
Oct 3, 2015, 10:16:53 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

Two operations are being done either way, either within stoi or within your code. Why should stoi be the one who is doing those two, instead of your code?

Also, stop top-posting. It makes it difficult to understand what you're responding to. Write your text under what you're responding to, not above it.

Nicol Bolas

unread,
Oct 3, 2015, 10:26:54 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 5:02:04 AM UTC-4, Vlad from Moscow wrote:
And here is a simple demonstrative program

#include <iostream>
#include <string>

int main()
{
    std::string s( "Here is number 100 you need to extract" );
   
    std::cout << stoul( s, s.find_first_of( "0123456789" ) ) << std::endl;   
}   
Its output is

100

It is very clear code with very clear semantic that does not create some unnecessary entities.

Each piece of the code also is very clear and does not arise a question.

It "arise a question[sic]" with me: what does `stoul` actually do with that integer? Yes, I see you find the first digit in the string. But it's unclear to me what `stoul` is supposed to do with it.

Whereas:

stoul( s.view().remove_prefix(s.find_first_of( "0123456789" )))

Makes it very clear what's going on.

Vlad from Moscow

unread,
Oct 3, 2015, 10:35:47 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com

On Saturday, October 3, 2015 at 5:16:53 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

These funtions already are designed specially for std::string. But they have a drawback. You can not specify a position in the string starting from which you are going to extract a number. This creates for example a difficulty of using the functions with the same string iteractively.
 
 
Two operations are being done either way, either within stoi or within your code. Why should stoi be the one who is doing those two, instead of your code?

Delegating this operation to the functions makes your code cleaner and more clear. You need not spend your time to implement the details. I am sure that a code that contans many implementation details is difficult to read. The code should clear demonstrate the imtention of the programmer.

Vlad from Moscow

unread,
Oct 3, 2015, 10:37:47 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
Are you serious? It looks like a joke.:) 

Nicol Bolas

unread,
Oct 3, 2015, 10:44:06 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 10:35:47 AM UTC-4, Vlad from Moscow wrote:
On Saturday, October 3, 2015 at 5:16:53 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

These funtions already are designed specially for std::string.

And that is 99% of what is wrong with those functions.

If you're going to add new overloads for these functions, those overloads should not exacerbate the existing flaws; they should fix them.

Taking string_view (or becoming template functions that take basic_string_views) would be a far more reasonable proposal than what you're talking about.

Two operations are being done either way, either within stoi or within your code. Why should stoi be the one who is doing those two, instead of your code?

Delegating this operation to the functions makes your code cleaner and more clear.

"cleaner and more clear" is a matter of personal opinion. Code that tells me exactly what it's doing is "cleaner and more clear" to me. If you get a view and remove prefix characters from it, I know what you're doing.

If you pass an integer to a function, I have to look up its documentation to find out what it's doing. That's not "more clear" to me.

Sam Kellett

unread,
Oct 3, 2015, 11:12:52 AM10/3/15
to std-pr...@isocpp.org
On 3 October 2015 at 15:44, Nicol Bolas <jmck...@gmail.com> wrote:
On Saturday, October 3, 2015 at 10:35:47 AM UTC-4, Vlad from Moscow wrote:
On Saturday, October 3, 2015 at 5:16:53 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

These funtions already are designed specially for std::string.

And that is 99% of what is wrong with those functions.
 
[snip]

If you pass an integer to a function, I have to look up its documentation to find out what it's doing. That's not "more clear" to me.

this is even more confusing when it's a function that does something with integers... am i passing in a default value if it fails? or a base that the input is in? etc, etc..?

Vlad from Moscow

unread,
Oct 3, 2015, 11:16:17 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com

On Saturday, October 3, 2015 at 5:44:06 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 10:35:47 AM UTC-4, Vlad from Moscow wrote:
On Saturday, October 3, 2015 at 5:16:53 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

These funtions already are designed specially for std::string.

And that is 99% of what is wrong with those functions.

Could you elaborate what is wrong with this? Maybe the C++ Standard has a defect placing these functions in the header <string>. 
 
If you're going to add new overloads for these functions, those overloads should not exacerbate the existing flaws; they should fix them.

As for me then I see that the overloads make the functions more flexible. It is what I always need when a number is inside a string.
 
Taking string_view (or becoming template functions that take basic_string_views) would be a far more reasonable proposal than what you're talking about.

Two operations are being done either way, either within stoi or within your code. Why should stoi be the one who is doing those two, instead of your code?

Delegating this operation to the functions makes your code cleaner and more clear.

"cleaner and more clear" is a matter of personal opinion. Code that tells me exactly what it's doing is "cleaner and more clear" to me. If you get a view and remove prefix characters from it, I know what you're doing.

If you pass an integer to a function, I have to look up its documentation to find out what it's doing. That's not "more clear" to me.

Without any doubts to understand your example shown above a programmer needs to read tons of the documentation. At least he must be sure that the functions you used have not some side effects.

To use a string followed by a position in the string is very natural because this pattern is used in many functions of class std:;string.

The code you showed has nothing common with the class std::string. It only makes the program more confused because you introduced a new entity that is not required to convert a string to an arithmetic type. 

Vlad from Moscow

unread,
Oct 3, 2015, 11:29:38 AM10/3/15
to ISO C++ Standard - Future Proposals
Oh, yes of course!:) s.find_first_of( "0123456789" ) evidently supplies the default value.

And what will you say about such functions like substr, append etc or for example s.find( 'A', pos )? I am sure it is very difficult to understand what pos means in the find. Is it a default value in the case if the find  will not find 'A'? What do you think about this?:)

Vlad from Moscow

unread,
Oct 3, 2015, 11:41:28 AM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
This family of conversion functions is an adaptation of the corresponding C functions for class std::string.

C function deal with pointers and you can very easy to move the pointer along a string.

However to do the same with objects std::string you need one more argument that specifies a position within the string.

Otherwise you need to create a new object or to descend to the level of C code or to introduce a new entity as you are trying to do for this simple task.

But class std::string already has all what it needs to do the task. The only thing you need to provide is to allow the class to use its own features.
 

Nicol Bolas

unread,
Oct 3, 2015, 1:44:32 PM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 11:16:17 AM UTC-4, Vlad from Moscow wrote:

On Saturday, October 3, 2015 at 5:44:06 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 10:35:47 AM UTC-4, Vlad from Moscow wrote:
On Saturday, October 3, 2015 at 5:16:53 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

These funtions already are designed specially for std::string.

And that is 99% of what is wrong with those functions.

Could you elaborate what is wrong with this? Maybe the C++ Standard has a defect placing these functions in the header <string>.

I thought it would be obvious.

These functions only work with std::string. They don't work with other string type that anyone has ever written. They don't work with std::basic_string<char, ..., MyAllocator>. They don't even have overloads for `std::u16string` or `std::u32string`.

std::basic_string is, first and foremost, a container. It manages how character data gets stored. Why should `stoi` care how character data gets stored, allocated, or anything of that nature? All `stoi` needs is a way to access a character array.

It's asinine to have to waste time copying a string just because `stoi` has an over-constrained interface. We don't need to over-constrain the interface more.
 
 
If you're going to add new overloads for these functions, those overloads should not exacerbate the existing flaws; they should fix them.

As for me then I see that the overloads make the functions more flexible. It is what I always need when a number is inside a string.

No, it makes them less flexible. It only allows offsetting from the beginning, not the end.

Just because something is "what I always need" does not mean that it is "flexible".
 
 
Taking string_view (or becoming template functions that take basic_string_views) would be a far more reasonable proposal than what you're talking about.

Two operations are being done either way, either within stoi or within your code. Why should stoi be the one who is doing those two, instead of your code?

Delegating this operation to the functions makes your code cleaner and more clear.

"cleaner and more clear" is a matter of personal opinion. Code that tells me exactly what it's doing is "cleaner and more clear" to me. If you get a view and remove prefix characters from it, I know what you're doing.

If you pass an integer to a function, I have to look up its documentation to find out what it's doing. That's not "more clear" to me.

Without any doubts to understand your example shown above a programmer needs to read tons of the documentation. At least he must be sure that the functions you used have not some side effects.

... what kind of side effects would any sane implementation have of a function called `find_first_of`?

There's defensive coding, and then there's paranoid coding. You're talking about the latter. If you assume that behind every possible function call lurks a sleeping Cthulhu ready to tear your code apart, you'll never get anywhere.
 
To use a string followed by a position in the string is very natural because this pattern is used in many functions of class std:;string.

And every single such function also has an overload that takes an iterator rather than an integer. Are you now suggesting we do that too?

It should be noted that many people don't like std::string's interface. So defending your position by citing its interface is like saying "look at how that garbage dump works. We need to make our code look like that!"

It should also be noted that every such function is a member function of std::basic_string. Thus, the integer value is clearly associated with the string. It's not "string followed by a position". It's `string.func_name(position)`. That's a very different thing.

`stoi` is a non-member function.
 
The code you showed has nothing common with the class std::string.

You say that as though std::string's interface were something to boast about ;)
 
It only makes the program more confused because you introduced a new entity that is not required to convert a string to an arithmetic type.

That's an implementation detail. Also, if stoi were implemented sanely, you'd already be implicitly constructing a string_view.

Nicol Bolas

unread,
Oct 3, 2015, 1:48:22 PM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 11:41:28 AM UTC-4, Vlad from Moscow wrote:
This family of conversion functions is an adaptation of the corresponding C functions for class std::string.

C function deal with pointers and you can very easy to move the pointer along a string.

However to do the same with objects std::string you need one more argument that specifies a position within the string.

If I wanted to code in C, I would be coding in C.

C++ has ways of dealing with functions that need access to a sequence in such a way that does not modify said sequence. We call them "ranges". std::string_view is such a range.

Vlad from Moscow

unread,
Oct 3, 2015, 2:41:38 PM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 8:44:32 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 11:16:17 AM UTC-4, Vlad from Moscow wrote:

On Saturday, October 3, 2015 at 5:44:06 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 10:35:47 AM UTC-4, Vlad from Moscow wrote:
On Saturday, October 3, 2015 at 5:16:53 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 4:35:08 AM UTC-4, Vlad from Moscow wrote:
It is a wrong point of view. I am not trying to do ywo operations. I am delegating this work to stoi.

And why should stoi be concerned with anything but converting a string to an integer? Why should it be concerned with offsetting the initial position of that string by some value first?

These funtions already are designed specially for std::string.

And that is 99% of what is wrong with those functions.

Could you elaborate what is wrong with this? Maybe the C++ Standard has a defect placing these functions in the header <string>.

I thought it would be obvious.

These functions only work with std::string.

And what? And what I am speaking about? I am speaking about std::string and the functions that deal with the std::string.

 
They don't work with other string type that anyone has ever written. They don't work with std::basic_string<char, ..., MyAllocator>. They don't even have overloads for `std::u16string` or `std::u32string`.

std::basic_string is, first and foremost, a container. It manages how character data gets stored. Why should `stoi` care how character data gets stored, allocated, or anything of that nature? All `stoi` needs is a way to access a character array.

It's asinine to have to waste time copying a string just because `stoi` has an over-constrained interface. We don't need to over-constrain the interface more.
 
 
If you're going to add new overloads for these functions, those overloads should not exacerbate the existing flaws; they should fix them.

As for me then I see that the overloads make the functions more flexible. It is what I always need when a number is inside a string.

No, it makes them less flexible. It only allows offsetting from the beginning, not the end.

Till now I thought that if I am allowed to do one more thing then my possibilities are enlarged. You are trying to disprove that.:)
  
Just because something is "what I always need" does not mean that it is "flexible".
 
 
Taking string_view (or becoming template functions that take basic_string_views) would be a far more reasonable proposal than what you're talking about.

Two operations are being done either way, either within stoi or within your code. Why should stoi be the one who is doing those two, instead of your code?

Delegating this operation to the functions makes your code cleaner and more clear.

"cleaner and more clear" is a matter of personal opinion. Code that tells me exactly what it's doing is "cleaner and more clear" to me. If you get a view and remove prefix characters from it, I know what you're doing.

If you pass an integer to a function, I have to look up its documentation to find out what it's doing. That's not "more clear" to me.

Without any doubts to understand your example shown above a programmer needs to read tons of the documentation. At least he must be sure that the functions you used have not some side effects.

... what kind of side effects would any sane implementation have of a function called `find_first_of`?

There's defensive coding, and then there's paranoid coding. You're talking about the latter. If you assume that behind every possible function call lurks a sleeping Cthulhu ready to tear your code apart, you'll never get anywhere.
 
I am talking about that you are trying to sell me a fur coat when i need only a missing button .:) And it looks like you will still try to sell your  fur coat if somebody else ask you about fot rxample gloves.:) I would not say that who needs a missing button is a paranoic fot the reason that he does not want to buy your fur coat.:) 

And it looks like  
To use a string followed by a position in the string is very natural because this pattern is used in many functions of class std:;string.

And every single such function also has an overload that takes an iterator rather than an integer. Are you now suggesting we do that too?

It should be noted that many people don't like std::string's interface. So defending your position by citing its interface is like saying "look at how that garbage dump works. We need to make our code look like that!"

I really feel for this people.:) But why should I suffer if somebody do not like the string's interface? All I want Is to specify a position in a string. May I do this?

 
It should also be noted that every such function is a member function of std::basic_string. Thus, the integer value is clearly associated with the string. It's not "string followed by a position". It's `string.func_name(position)`. That's a very different thing.

`stoi` is a non-member function.

Yes stoi is not a member function. But it is designed to work with strings that can contain at some position a number.:) 
 
The code you showed has nothing common with the class std::string.

Really?:)

Vlad from Moscow

unread,
Oct 3, 2015, 2:46:03 PM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
I need not a range. I need just a position.:) 

Thiago Macieira

unread,
Oct 3, 2015, 2:54:08 PM10/3/15
to std-pr...@isocpp.org
On Saturday 03 October 2015 11:46:02 Vlad from Moscow wrote:
> > C++ has ways of dealing with functions that need access to a sequence in
> > such a way that does not modify said sequence. We call them "ranges".
> > std::string_view is such a range.
>
> I need not a range. I need just a position.:)

Why do you need a begin pointer and an offset from that begin pointer? Why not
adjust the begin pointer by the offset amount and send only one piece of
information to the function?

--
Thiago Macieira - thiago (AT) macieira.info - thiago (AT) kde.org
Software Architect - Intel Open Source Technology Center
PGP/GPG: 0x6EF45358; fingerprint:
E067 918B B660 DBD1 105C 966C 33F5 F005 6EF4 5358

Vlad from Moscow

unread,
Oct 3, 2015, 3:02:48 PM10/3/15
to ISO C++ Standard - Future Proposals
I have no begin pointer. I have a string and a position in the string. It is a disposable operation. I need not to introduce some other entities when I already have all I need.

Nicol Bolas

unread,
Oct 3, 2015, 5:20:42 PM10/3/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
On Saturday, October 3, 2015 at 2:41:38 PM UTC-4, Vlad from Moscow wrote:
On Saturday, October 3, 2015 at 8:44:32 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 11:16:17 AM UTC-4, Vlad from Moscow wrote:

On Saturday, October 3, 2015 at 5:44:06 PM UTC+3, Nicol Bolas wrote:
On Saturday, October 3, 2015 at 10:35:47 AM UTC-4, Vlad from Moscow wrote:
These funtions already are designed specially for std::string.

And that is 99% of what is wrong with those functions.

Could you elaborate what is wrong with this? Maybe the C++ Standard has a defect placing these functions in the header <string>.

I thought it would be obvious.

These functions only work with std::string.

And what? And what I am speaking about? I am speaking about std::string and the functions that deal with the std::string.

... Please take note of the part of the conversation you're replying to. I said that those functions being designed only for std::string was exactly what was wrong with it. You asked for elaboration. And I offered it.

So how does your statement make sense in that context? I responded to the exact question you asked, then you claim that my response is irrelevant.

Yes, `stoi` and such are designed for std::string. That is what is wrong with them. People need to be able to convert any string to integers/floats/etc, not just std::string. That's why it is wrong for them to be designed for std::string.

I am talking about that you are trying to sell me a fur coat when i need only a missing button .:)

No, I want to see improvements to `stoi` that will solve your problem and those of other people.

See the difference? You getting the bare minimum needed to help you only helps you. Getting stoi and friends to work with string_view helps you and helps tons of other people.

Standard library features need to service the needs of more than yourself.

Thiago Macieira

unread,
Oct 3, 2015, 5:40:30 PM10/3/15
to std-pr...@isocpp.org
On Saturday 03 October 2015 12:02:48 Vlad from Moscow wrote:
> I have no begin pointer. I have a string and a position in the string. It
> is a disposable operation. I need not to introduce some other entities when
> I already have all I need.

The string contains a begin pointer.

What's more understandable:

stoi(str, 16, nullptr, 10);
or
stoi(str.mid(16), nullptr, 10);
?

Remember code is read more often than it is written. Having the position
clearly marked is a bonus, so you wouldn't misinterpret it as the base.

(I know there's no std::string::mid() function, but that's a deficiency to be
addressed elsewhere and also a bit of a philosophical discussion)

Vlad from Moscow

unread,
Oct 4, 2015, 5:34:24 AM10/4/15
to ISO C++ Standard - Future Proposals, mwoehlk...@gmail.com
The functions initially shall be declared with the parameter pos. It is a serious standard defect.

So I am going to remedy this defect. It does not depend on whether it is helpful personally for you or not. 

In fact the functions is useless in most cases and the programmers have to descend to the C level and use for example C function strtoul directly instead of stoul. So they do not deal with the std::string. They deal with char *. And moreover in this case the parameter idx is also useless from the point of view of using objects of type std::string.

It is enough to add one more parameter to the functions and the situation is changed dramatically.

Here is a simple example. I wrote a simplified implementation of the overloaded stoul that to demonstrate just the idea.

#include <iostream>
#include <string>

unsigned long stoul( const std::string &s, std::string::size_type pos, size_t* idx = 0, int base = 10 )
{
    const char *nptr = s.c_str();
    char *end_ptr;
   
    unsigned long value = std::strtoul( nptr + pos, ( idx == 0 ? NULL : &end_ptr ), base );
   
    if ( idx ) *idx = end_ptr - nptr;
   
    return value;
}

int main()
{
    const char *digits = "0123456789";
    std::string s( "#1, ##2, ###3, ####4, #####5" );

    size_t n = 0;
    for ( std::string::size_type pos = 0; ( pos = s.find_first_of( digits, pos ) ) != std::string::npos; )
    {
        std::cout << ::stoul( s, pos, &pos ) << ' ';
        ++n;
    }

    std::cout << "\nThere are " << n << " numbers in the string" << std::endl;
   
    std::cout << "The first number is " << ::stoul( s, s.find_first_of( digits ) ) << std::endl;
    std::cout << "The last number is  " << ::stoul( s, s.find_last_of( digits ) ) << std::endl;
}   

The program output is

1 2 3 4 5
There are 5 numbers in the string
The first number is 1
The last number is  5

There is no any need to introduce new entities that to do this simple task. All is done in the frames of the class std::string because all already exists and is enough to do the task.

This idiom

while ( ( pos = s.find_first_of( something, pos ) ) != std::string::npos )
{
    /*...*/
}

or

while ( ( pos = s.find( something, pos ) ) != std::string::npos )
{
    /*...*/
}

occurs numerous times in the code base and very clear for all programmers.

Here is the string itself that is accentuated.

stoul is in fact a static method of the class std::string. It serves objects of the type.

They need not a third entity or even more entities to do the task.

Keep It Simple, Stuipid!:)

As for this code

stoul( s.view().remove_prefix(s.find_first_of( "0123456789" )))


then it is simply very awful.

For example

What and where does remove_prefix remove?

Is s being changed?

Why is there used remove_prefix when we were not going to remove anything in our string?

How to use the next position in the string?

Wnat will be with s after this statement?

Why are we introducing new entities like view and remove_prefix when we already have all what we need?

What idx will the call return?

Will this idx be valid for the view or for the original string?

And at last but not least

How does the overloaded functions prevent you to use such awful or as you think splendid code?:)
 

Vlad from Moscow

unread,
Oct 4, 2015, 5:44:04 AM10/4/15
to ISO C++ Standard - Future Proposals
This statement

        stoi(str, 16, nullptr, 10); 

can be rewritten for example like

 
        stoi(str, pos, &pos, 10);

But even the original statement is more clear than
 
        stoi(str.mid(16), nullptr, 10);

because nobody knows what is str.mid 

Does it search the middle of the substring starting at position 16 of the original string?

And moreover it is not necessary that used index is indeed is in the middle of the string.

Vlad from Moscow

unread,
Oct 4, 2015, 7:06:51 AM10/4/15
to ISO C++ Standard - Future Proposals


On Sunday, October 4, 2015 at 12:40:30 AM UTC+3, Thiago Macieira wrote:
There is a very simple and efficient method to determine what approach is more intuitively clear.

Just give a corresponding assignment to a beginner and look how  he will try to do it.

So if you ask a beginner to output all numbers in a string I assure you that his approach will look something like the following

#include <iostream>
#include <string>

unsigned long get_number( const std::string &s, std::string::size_type &pos )
{
    unsigned long value = 0;
   
    for ( ; s[pos] >= '0' && s[pos] <= '9'; ++pos ) value = 10 * value + s[pos] - '0';
          
    return value;
}
          
int main()
{

    std::string s( "#1, ##2, ###3, ####4, #####5" );
    size_t n = 0;
   
    for ( std::string::size_type pos = 0; pos != s.size(); )
    {
        if ( s[pos] >= '0' && s[pos] <= '9' )
        {
            std::cout << get_number( s, pos ) << ' ';
            ++n;
        }
        else
        {
            ++pos;

        }
    }       
           
    std::cout << "\nThere are " << n << " numbers in the string" << std::endl;
}   

The word "remove" or "view" will never in his life come to his head relative to this assignment. :)

So just substitute get_number for std::stoul specifying in it the second parameter that defines a position in the string  and you will get very clear code for programmers of any level of qualification.:)

Bengt Gustafsson

unread,
Oct 4, 2015, 7:29:54 AM10/4/15
to ISO C++ Standard - Future Proposals
I think this kills the suggestion, which involves these overloads:

int stoi(const string& str, size_t* idx = 0, int base = 10);

int stoi(const string& str, std::string::size_type pos, size_t* idx = 0, int base = 10);


But now:

int v = stoi(str, NULL);

results in a "ambiguous call" error. This is going to break quite a lot of code, I think. (the reason being #define NULL 0)

Given the existence of string_view::remove_prefix() I think a more interesting discussion is whether there should be an overload:

stoi(string_view& str, int base = 10);

which uses str.remove_prefix() to indicate how much of the input string was consumed. This would be a "breaking" change but only visavi code that has not been written yet and that could assume
that a lvalue string_view passed to stoi() is not to be touched. I think it would be possible to understand that stoi will change the string_view if possible. And it provides a very easy to use API for string to number parsing.



Den fredag 2 oktober 2015 kl. 17:27:01 UTC+2 skrev Vlad from Moscow:
The C++ Standard includes a family of conversion functions like std::stoi, std::stol, std::stoul and other similar functions.

They allow to convert a string to some arithmetic type.

However it is not always convinient to use them when you are going to apply the function to a string starting from some non-zero position.

In this case you need to use either member function substr to get the desired substring. or to use another member function c_str that to apply the corresponding C function instead of the C++ function.

So I think you have already understood that I want to suggest overloading functions that have one more parameter that specifies a position in the string.

For example function stoi can now  look like

int stoi(const string& str, size_t* idx = 0, int base = 10);

int stoi(const string& str, std::string::size_type pos, size_t* idx = 0, int base = 10);

Vlad from Moscow

unread,
Oct 4, 2015, 8:03:31 AM10/4/15
to ISO C++ Standard - Future Proposals


On Sunday, October 4, 2015 at 2:29:54 PM UTC+3, Bengt Gustafsson wrote:
I think this kills the suggestion, which involves these overloads:

int stoi(const string& str, size_t* idx = 0, int base = 10);

int stoi(const string& str, std::string::size_type pos, size_t* idx = 0, int base = 10);


But now:

int v = stoi(str, NULL);

results in a "ambiguous call" error. This is going to break quite a lot of code, I think. (the reason being #define NULL 0)

It is a good remark but I very doubt that it will indeed break quite a lot of code.

 I never saw such a record like

int v = stoi(str, NULL);

But in any case if such a statement is present in some code the compiler will issue an error.

And moreover there is one more positive moment.:) This stimulates to use nullptr instead of NULL.

Given the existence of string_view::remove_prefix() I think a more interesting discussion is whether there should be an overload:

stoi(string_view& str, int base = 10);

which uses str.remove_prefix() to indicate how much of the input string was consumed. This would be a "breaking" change but only visavi code that has not been written yet and that could assume
that a lvalue string_view passed to stoi() is not to be touched. I think it would be possible to understand that stoi will change the string_view if possible. And it provides a very easy to use API for string to number parsing.

 
Words "constant" and "remove" contradict each other and using them simultaneously with the same object looks like a bug.

And as I pointed out early it is not clear what idx means in this case.

Nicol Bolas

unread,
Oct 4, 2015, 10:18:53 AM10/4/15
to ISO C++ Standard - Future Proposals
On Sunday, October 4, 2015 at 7:06:51 AM UTC-4, Vlad from Moscow wrote:
There is a very simple and efficient method to determine what approach is more intuitively clear.
 
Just give a corresponding assignment to a beginner and look how  he will try to do it. 

Wait, you said "intuitively clear" at first. Then you switched to talking about "beginners".

Beginners are beginners precisely because they have no experience. And experience is how you develop intuition, and thus how you know what is "intuitively clear" and what is not.

I'm an experienced C++ programmer, and the code you posted is mud to me. It is by no reasonable definition of the word "clear". It most certainly is not "intuitively clear". Oh, I can figure out what it's doing by staring at it for a while.

But it is trash code. You may argue that it's the kind of trash code that a beginner would write, but that only proves my point: beginners don't know what clear code looks like.

You're using the wrong standard to evaluate whether code is clear or not.
 
So if you ask a beginner to output all numbers in a string I assure you that his approach will look something like the following

I contest your notion that this is what any beginner would write. Oh, this is what some beginners would write, to be sure. But those beginners would be beginners at C programming, not C++ programming. Even pre-C++11 C++.

Any beginner from one of Bjarne's intro classes would never write such filth (they'd be using iterators). Any beginner who bothered to actually look at the documentation of std::string would have found string search functions and would use them. Any beginner who had been paying attention to C++ at all would avoid such code.

There is a difference between "beginner" and "ignoramus". The programmer you cite seems to be the latter. And those are not programmers we should cater to.

We should not encourage abusive use of the API. We should not encourage ignorance or sloth among programmers. We should not add library features that only cater to C-in-C++-style programmers.

Your suggestion helps nobody but them.

Beginners can learn to properly use the API. Bjarne proves that every year with his beginning programming classes. They can be trained to use iterators, ranges, and so forth. We should make these features available, not for advanced programmers, but for beginners too.

Because beginners are the ones who will make the most mistakes. Just look at all that code you posted. Few beginners would get that right the first time. Or second. They'll waste hours trying to figure out where they went wrong.

Whereas this code is much easier to write and read, and has fewer points for mistakes:

std::string s = ...;
auto sv = std::string_view(s);

while(true)
{
 
auto ix = sv.find_first_of("0123456789");
 
if(ix == std::string::npos) break;
 
sv = sv.remove_prefix(ix);

  int advance;
  auto value = stoi(sv, &advance);
  sv = sv.remove_prefix(advance);

  std
::cout << value << " ";
}

Shorter code. Less places to screw up. This is what beginners ought to be writing. Beginners can learn to do this if you actually teach them the API.

Your way assumes that beginners only know that strings are an array of characters with a size. My way assumes that beginners know that strings are objects with actual functions. Your way assumes ignorance and sloth; my way does not.

Your way leads inevitably to brittle code, difficult-to-modify code, and bad programmers. My way encourages the use of robust code, easy-to-modify code, and good programmers.

So why should we do things your way?

Vlad from Moscow

unread,
Oct 4, 2015, 11:39:25 AM10/4/15
to ISO C++ Standard - Future Proposals
Beginners select a straightforward approach. And even professional programmers when they encouter a new task first of all try to use those knoweledge they have that is they select a straightforward approach.

There is no any need to envent new entities if you have already all to resolve a problem. New things are invented only in case when you can not resolve a problem.

remove_prefix has nothing common with the problem because the task is not to remove something in a string. A string with numbers has nor prefix nor suffix and it shall be unchanged.

So using remove_prefix is simply an invalid idiom for this task.

The task is done simply as the code of a beginner that I showed does.

At first you have to find the position of a number and then extract the number.  That is all.

To find a position is an immutable operation. To extract a number is also immutable operation.

What are you going to remove?!

Moreover you even do not see that your code does not make sense because all what you are doing is inventing new enity string_view just to write

  auto value = stoi(sv, &advance);


instead of

  auto value = stoi( s, pos, &pos );


My congratulations!:)  It is a great achievment in programming!:)




Nicol Bolas

unread,
Oct 4, 2015, 12:00:01 PM10/4/15
to ISO C++ Standard - Future Proposals
OK, it's clear we're talking past each other at this point. You prefer C-in-C++ style. You prefer convoluted code that ignores the API and is "straightforward," as defined by what poorly taught beginning programmers will tend to write.

The standards committee doesn't agree with you. They prefer ranges to passing bare integer indices around. They prefer safe coding idioms. Coding idioms that are easy to reason about and modify. Even if they introduce "new entities" or whatever.

Go ahead and write up a formal proposal if you want. You'll have to fly to a meeting and defend it, as I rather suspect you'll have a hard time finding people to defend it for you. And don't be surprised if the first comment out of the committee is, "why don't you just take a `string_view`?" And when you try to offer your justifications for your API, don't be surprised if they find it unconvincing.

Vlad from Moscow

unread,
Oct 4, 2015, 12:54:50 PM10/4/15
to ISO C++ Standard - Future Proposals
I hope that the C++ Standards Committee is not just you.:)

All what you have written now has nothing common with the discussion.

The redundant and senseless operation remove_prefix  does not make the code safer.:)

And your words that "They prefer ranges to passing bare integer indices around" after seeing your code as for example

  auto ix = sv.find_first_of("0123456789");
 
if(ix == std::string::npos) break;
 
sv = sv.remove_prefix(ix);

  int advance;
  auto value = stoi(sv, &advance);
  sv = sv.remove_prefix(advance);

looks like a joke. :)

Could you say what is ix? Is it an integer?
And what about advance? Oh, I am sorry, it is not an integer, is it ?

In fact your code diifers from the code of a beginner that I showed  only in one thing: the code of the beginner does not use remove_prefix that you are uisng twice in one loop

  //...
  sv = sv.remove_prefix(ix);

  int advance;
  auto value = stoi(sv, &advance);
  sv = sv.remove_prefix(advance);
  //...

By the way what about if you need not only to extract numbers but also to generate a vector of pairs { position, number }?

Will ix in your code correspond to the position in the original string? Or in this case do you have to rewrite your code entirely?:)



Vlad from Moscow

unread,
Oct 4, 2015, 2:25:17 PM10/4/15
to ISO C++ Standard - Future Proposals
Instead of saying many words let's compare the two resulting code snippets.

This is better than any words.:)

This is your resulting code snippet

std::string s = ...;
auto sv = std::string_view(s);

while(true)
{
 
auto ix = sv.find_first_of("0123456789");
 
if(ix == std::string::npos) break;
 
sv = sv.remove_prefix(ix);

  int advance;
  auto value = stoi(sv, &advance);
  sv = sv.remove_prefix(advance);

  std
::cout << value << " ";
}

And this is my resulting code snippet

    std::string s = ...;

    for ( std::string::size_type pos = 0;
          ( pos = s.find_first_of( "0123456789", pos ) ) != std::string::npos; )
    {
        std::cout << std::stoul( s, pos, &pos ) << ' ';
    }


I can use the same code to generate for example a vector of pairs { position, number } iust substituting the statement inside the body of the loop for

v.push( { pos, std::stoul( s, pos, &pos ) } );

And what about your code?




Nicol Bolas

unread,
Oct 4, 2015, 8:23:46 PM10/4/15
to ISO C++ Standard - Future Proposals
On Sunday, October 4, 2015 at 12:54:50 PM UTC-4, Vlad from Moscow wrote:
On Sunday, October 4, 2015 at 7:00:01 PM UTC+3, Nicol Bolas wrote:
OK, it's clear we're talking past each other at this point. You prefer C-in-C++ style. You prefer convoluted code that ignores the API and is "straightforward," as defined by what poorly taught beginning programmers will tend to write.

The standards committee doesn't agree with you. They prefer ranges to passing bare integer indices around. They prefer safe coding idioms. Coding idioms that are easy to reason about and modify. Even if they introduce "new entities" or whatever.

Go ahead and write up a formal proposal if you want. You'll have to fly to a meeting and defend it, as I rather suspect you'll have a hard time finding people to defend it for you. And don't be surprised if the first comment out of the committee is, "why don't you just take a `string_view`?" And when you try to offer your justifications for your API, don't be surprised if they find it unconvincing.

I hope that the C++ Standards Committee is not just you.:)

The C++ standards committee does not even include me ;)

However, the fact of the matter is this. You explained what you wanted. Six separate people, including myself, disagree with you about which is clearer, easier for beginners, and/or more useful in general. Not one single person has stepped forward to defend your idea.

Do you honestly expect the arguments that we have found unconvincing to be more convincing when spoken to committee members? They will undoubtedly ask why you don't just suggest that the function takes a `string_view` (especially since that change is already part of an existing proposal).

Do you think that your examples will convince them? Do you believe that the people behind the range proposal will be convinced by your C-in-C++ code examples? Do you think that they will agree with you when you declare how beginners will obviously want to code?

Because at the end of the day, all you have is a feature who's functionality will be duplicated once `string_view` is added to `stoi` and so forth. You may not like the form of that duplication, but it is an irrefutable fact that you will be able to get the same job done with the `string_view` form as with what you want.

That's what you'd be fighting against.
 
In fact your code diifers from the code of a beginner that I showed  only in one thing: the code of the beginner does not use remove_prefix that you are uisng twice in one loop

You were trying to prove that beginners would never be able to use string_view, right? So if it is true that my code is only slightly different from your idea of beginner code, then you must accept that a beginner would be equally capable of writing either one.

Doesn't that torpedo your entire argument? Either my code is so different that a beginner would never write it, or it's perfectly comprehensible to a beginner. It can't be both.
 
By the way what about if you need not only to extract numbers but also to generate a vector of pairs { position, number }?

That right there shows the problem with your mode of thought. You declare arbitrary requirements without bothering to ask why someone would need such a requirement.

I look at that requirement and ask what they'd do with such offsets. If they want to associate locations in the string with the number that they correspond to, then odds are good that they're probably going to want to process the text between number characters. Right? I mean, they already have the numbers themselves. So that would be a logical reason for wanting to know what part of the text a number comes from.

And if that's the case, then `{ position, number }` is seriously lacking one important element: the size of each number, in characters. You need that to know where a number ends, so that you can go on to process the characters after one number and before the next.

Given that, what you really want is a `vector<pair<string_view, int>>`. And that is easy to provide:

vec.emplace_back(sv.substr(0, advance), value);
 
Will ix in your code correspond to the position in the original string? Or in this case do you have to rewrite your code entirely?:)
Offsets (stop calling them "positions"), despite what I said, are a valid way of interacting with strings. Unlike iterators, they can't be invalidated (so long as you didn't modify the text they represent). Therefore, wanting to actually return the offset to each entry is not a priori unreasonable.

It's also pretty trivial with `string_view`:

vec.emplace_back(&sv[0] - &s[0], value);

What, did you forget that `string_view`, for all of its interface, is really just a pair of pointers ;)


On Sunday, October 4, 2015 at 2:25:17 PM UTC-4, Vlad from Moscow wrote:
Instead of saying many words let's compare the two resulting code snippets.

This is better than any words.:)

You're absolutely right; your code communicates far better than any words could. And here is the result of your communication.

I cannot rationally discuss issues of code quality with someone who genuinely feels that this:
 
    std::string s = ...;

    for ( std::string::size_type pos = 0;
          ( pos = s.find_first_of( "0123456789", pos ) ) != std::string::npos; )
    {
        std::cout << std::stoul( s, pos, &pos ) << ' ';
    }

is an example of good code.

Good day, sir!

Vlad from Moscow

unread,
Oct 5, 2015, 6:25:48 AM10/5/15
to ISO C++ Standard - Future Proposals


On Monday, October 5, 2015 at 3:23:46 AM UTC+3, Nicol Bolas wrote:
On Sunday, October 4, 2015 at 12:54:50 PM UTC-4, Vlad from Moscow wrote:
On Sunday, October 4, 2015 at 7:00:01 PM UTC+3, Nicol Bolas wrote:
OK, it's clear we're talking past each other at this point. You prefer C-in-C++ style. You prefer convoluted code that ignores the API and is "straightforward," as defined by what poorly taught beginning programmers will tend to write.

The standards committee doesn't agree with you. They prefer ranges to passing bare integer indices around. They prefer safe coding idioms. Coding idioms that are easy to reason about and modify. Even if they introduce "new entities" or whatever.

Go ahead and write up a formal proposal if you want. You'll have to fly to a meeting and defend it, as I rather suspect you'll have a hard time finding people to defend it for you. And don't be surprised if the first comment out of the committee is, "why don't you just take a `string_view`?" And when you try to offer your justifications for your API, don't be surprised if they find it unconvincing.

I hope that the C++ Standards Committee is not just you.:)

The C++ standards committee does not even include me ;)

Thanks, it is indeed a good news.:) 

However, the fact of the matter is this. You explained what you wanted. Six separate people, including myself, disagree with you about which is clearer, easier for beginners, and/or more useful in general. Not one single person has stepped forward to defend your idea.

I am dissapointed!  Six is too few.:).
 
Do you honestly expect the arguments that we have found unconvincing to be more convincing when spoken to committee members? They will undoubtedly ask why you don't just suggest that the function takes a `string_view` (especially since that change is already part of an existing proposal).

I think that if somebody can write code will not ask such questions. It is enough to see your code only once that never ask such questions. Take into account that my proposal is not about remove_prefix.:) And my code removes nothing.:)

 
Do you think that your examples will convince them? Do you believe that the people behind the range proposal will be convinced by your C-in-C++ code examples? Do you think that they will agree with you when you declare how beginners will obviously want to code?

Till now I thought that it is your code that is a bad C++ in C.:) It makes many redundant operations, uses many unnecessary integer variables.
 
Because at the end of the day, all you have is a feature who's functionality will be duplicated once `string_view` is added to `stoi` and so forth. You may not like the form of that duplication, but it is an irrefutable fact that you will be able to get the same job done with the `string_view` form as with what you want.

Nothing in my code duplicates string_view.

it seems you have understood nothing. Your approach is to add the fifth wheel to a coach  And moreover your fifth wheel has a form of an incorrect rectangle that results in using remove_prefix.:)

My approach is to use the coach with its four wheels. Only I suggest to use a new spring.:)


That's what you'd be fighting against.
 
In fact your code diifers from the code of a beginner that I showed  only in one thing: the code of the beginner does not use remove_prefix that you are uisng twice in one loop

You were trying to prove that beginners would never be able to use string_view, right?

No, I said that such an idea will never come in his head.:) If he has an assignment to find a position in a string and extract a number at the position he will do these two tasks:

1. Find the position;
2. Extract the number.


 
So if it is true that my code is only slightly different from your idea of beginner code, then you must accept that a beginner would be equally capable of writing either one.

A beginner can write any code.:) The problem is that he himself never will invent string_view in this situation.:) In the best case he will know that there is standard function stoi that he could use.
 

Doesn't that torpedo your entire argument? Either my code is so different that a beginner would never write it, or it's perfectly comprehensible to a beginner. It can't be both.

A bad code is being written in two cases. Either a programmer knows too little in programming. Or a programmer knows too much constructions but does not know how, where and why to use them.:)

 
By the way what about if you need not only to extract numbers but also to generate a vector of pairs { position, number }?

That right there shows the problem with your mode of thought. You declare arbitrary requirements without bothering to ask why someone would need such a requirement.

Any good code is a generic code. It is usually reusable.  So there is nothing wonderful that my code can be used with the new task without any serious changes and your code can not be used with the new task without  being entirely rewritten.

I look at that requirement and ask what they'd do with such offsets. If they want to associate locations in the string with the number that they correspond to, then odds are good that they're probably going to want to process the text between number characters. Right? I mean, they already have the numbers themselves. So that would be a logical reason for wanting to know what part of the text a number comes from.

And if that's the case, then `{ position, number }` is seriously lacking one important element: the size of each number, in characters. You need that to know where a number ends, so that you can go on to process the characters after one number and before the next.

Given that, what you really want is a `vector<pair<string_view, int>>`. And that is easy to provide:

vec.emplace_back(sv.substr(0, advance), value);
 
To provide this you have to rewrite all your previous code with remove_prefix.:)

Matthew Woehlke

unread,
Oct 5, 2015, 10:19:37 AM10/5/15
to std-pr...@isocpp.org
On 2015-10-03 17:40, Thiago Macieira wrote:
> (I know there's no std::string::mid() function, but that's a deficiency to be
> addressed elsewhere and also a bit of a philosophical discussion)

Um... substr? (Mind, I also prefer Qt's much better names, but unless I
miss something, it *does* exist. What *is* missing - because we don't
actually *have* string_view yet, and hopefully will be added along with
string_view - is a corresponding function to get a string_view from a
starting offset, a la QString::midRef.)

That said, right() does seem to be missing (taking 'left(n)' to be
shorthand for 'substr(0, n)' and therefore "unnecessary")...

--
Matthew

Matthew Woehlke

unread,
Oct 5, 2015, 10:48:02 AM10/5/15
to std-pr...@isocpp.org
On 2015-10-04 20:23, Nicol Bolas wrote:
> However, the fact of the matter is this. You explained what you wanted. Six
> separate people, including myself, disagree with you about which is
> clearer, easier for beginners, and/or more useful in general. Not one
> single person has stepped forward to defend your idea.

Hear, hear. I was about to mention that also.

On 2015-10-05 06:25, Vlad from Moscow wrote:
> I am dissapointed! Six is too few.:).

Six is the number of people that were willing to join the fray. The
remainder almost certainly a) agree with the majority view and so don't
feel the need to reply, as they would not be adding anything meaningful,
b) don't find the proposal of sufficient interest to bother reading the
thread (and so aren't likely to be supportive anyway), or c) are too
disgusted to want anything to do with the melee. Anyone else actually in
favor of your proposal would likely have spoken up by now.

On 2015-10-04 20:23, Nicol Bolas wrote:
> [...] at the end of the day, all you have is a feature who's
> functionality will be duplicated once `string_view` is added to `stoi` and
> so forth.

On top of which, the advent of string_view (and assuming it implicitly
constructs from std::string?) means we ought to be *deprecating
entirely* stoi(std::string, ...), because it is redundant and unnecessary.

You (Vlad) are fighting an uphill battle to expand an area of the
language that is on its way out the door. Lots of luck with that...

On 2015-10-05 06:25, Vlad from Moscow wrote:
> Any good code is a generic code. It is usually reusable.

Exactly. And string_view is (*much*!) more reusable and generic than
std::string.

--
Matthew

Matthew Woehlke

unread,
Oct 5, 2015, 10:55:06 AM10/5/15
to std-pr...@isocpp.org
On 2015-10-03 10:26, Nicol Bolas wrote:
> stoul( s.view().remove_prefix(s.find_first_of( "0123456789" )))

In fairness, that *is* a mess :-). An equivalent of QString::midRef
would be really nice here, i.e. a substr that returns a string_view
instead of a new string.

--
Matthew

Reply all
Reply to author
Forward
0 new messages