Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Re: Why std::string =3D?windows-1252?Q?doesn=3D92t_include_autom?= =3D =3D?windows-1252?Q?atic_conversion_from_the_standard_primitives=3D3F?=3D

30 views
Skip to first unread message

Gennaro Prota

unread,
Jul 7, 2010, 1:13:12 PM7/7/10
to
On 06/07/2010 10.30, Peng Yu wrote:
[...]

> I'm wondering why std::string doesn=92t include automatic conversion
> from the standard primitives.
>
> [...] Can I suggest to add this in future C++ standard? Where
> the suggestion should be sent to?
>

Nowhere: it's already "there" (waiting for approval). See the
Final Committee Draft for C++0x:

<http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf>

std::string foo = 123
>

But not in this form, of course. You'll have (barring a last
minute drop, or changes):

std::string s = std::to_string( i ) ;

The header to include is --just guess-- <string> itself (and not
<stdio.h> or <sprintf> :-)), which someone must have deemed not
crowded enough, either.

--
Gennaro Prota | name.surname yahoo.com
Breeze C++ (preview): <https://sourceforge.net/projects/breeze/>
Do you need expertise in C++? I'm available.


[ comp.std.c++ is moderated. To submit articles, try just posting with ]
[ your news-reader. If that fails, use
mailto:std...@netlab.cs.rpi.edu<std-c%2B%2...@netlab.cs.rpi.edu>
]
[ --- Please see the FAQ before posting. --- ]
[ FAQ: http://www.comeaucomputing.com/csc/faq.html ]

James Kanze

unread,
Jul 10, 2010, 3:56:14 AM7/10/10
to
On Jul 7, 6:13 pm, Gennaro Prota <name.surn...@yahoo.com> wrote:
> On 06/07/2010 10.30, Peng Yu wrote:
> [...]

> > I'm wondering why std::string doesn=92t include automatic conversion
> > from the standard primitives.

> > [...] Can I suggest to add this in future C++ standard? Where
> > the suggestion should be sent to?

> Nowhere: it's already "there" (waiting for approval). See the
> Final Committee Draft for C++0x:

> <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3092.pdf>

> std::string foo = 123

> But not in this form, of course. You'll have (barring a last
> minute drop, or changes):

> std::string s = std::to_string( i ) ;

The difference between an implicit conversion (which can cause
all sorts of problems with overload resolution) and an explicit
one.

The standard definition does, however, show one of the reason
why defining such functions is problematic. After implementing
the standard specification for double and calling it on 1E40 and
1E-40, I get:

as string: "10000000000000000303786028427003666890752.000000"
as string: "0.000000"

Neither are really useful output. (The default formatting for
std::ostream might be more generally useful, but until you know
more context, you can't really decide. For debugging, for
example, I'd prefer that the precision was increased.)

One also wonders why they didn't make it a template, so that
user defined classes (which define a << operator) are
automatically covered.

> The header to include is --just guess-- <string> itself (and not
> <stdio.h> or <sprintf> :-)), which someone must have deemed not
> crowded enough, either.

The header is <string>. Which is a little crowded, but mainly
crowded with the definition of std::basic_string itself, which
has a somewhat bloated interface. Once you've got the class
definition, the added free functions are quite reasonable
(although one might argue that the IO functions belong in
a separate file).

--
James Kanze

--


[ comp.std.c++ is moderated. To submit articles, try just posting with ]

[ your news-reader. If that fails, use mailto:std...@netlab.cs.rpi.edu]

Gennaro Prota

unread,
Jul 13, 2010, 2:02:19 AM7/13/10
to
On 10/07/2010 9.56, James Kanze wrote:
[...]

>>
>> > std::string foo = 123
>> > But not in this form, of course. You'll have (barring a last
>> > minute drop, or changes):
>> > std::string s = std::to_string( i ) ;
>
> The difference between an implicit conversion (which can cause
> all sorts of problems with overload resolution) and an explicit
> one.
>
> The standard definition does, however, show one of the reason
> why defining such functions is problematic. After implementing
> the standard specification for double and calling it on 1E40 and
> 1E-40, I get:
>
> as string: "10000000000000000303786028427003666890752.000000"
> as string: "0.000000"
>
> Neither are really useful output. (The default formatting for
> std::ostream might be more generally useful, but until you know
> more context, you can't really decide. For debugging, for
> example, I'd prefer that the precision was increased.)
>
> One also wonders why they didn't make it a template, so that
> user defined classes (which define a << operator) are
> automatically covered.

I see this as a "feature" for novices (but see below) and/or for
toy programs so I wouldn't consider support of UDTs as a goal in
itself. But a template would simplify both the implementation
(just one body and you'd be done) and the specification in the
standard (except possibly for fights on the choice of what to
throw :-)):

template< typename T >
string
to_string( T const & v )
{
stringstream s ;
if ( ! ( s << v ) ) {
throw something...
}
return s.str() ;
}

(all this reminds me of an old thread about library issue 434
where I showed among other things that you could write a simple
to_string for std::bitset, in some ten lines of code, using the
public interface only (and I'm not a genius, really)

<http://groups.google.com/group/comp.std.c++/msg/90e4ad2bebb4863d>

and all the replies were that adding some three overloads of it
was better... and simpler :-) I think me and the committee have
completely opposite views on what is complex and what is
simple.)

[Note:
the replies I'm hinting at were all from one person and /at
that time/ the publicly available comments on the issue (those
from <http://std.dkuug.dk/jtc1/sc22/wg21>) seemed to say that
the committee was on his same track (in fact, the comments even
alluded to a solution using a proxy object, just for love of
simplicity).

Eventually no overloads have been added but the solution is
plainly incorrect: I don't think that

ctype<wchar_t>::widen('0')
L'0'
and
(wchar_t)'0'

are required to be the same in all locales, as he said. No idea
when he proved that "theorem".]


More importantly, I guess it would simplify a lot the opposite
direction, which the draft deals with with a plethora of stoi,
stof, stoull and what-not (a step of some decades back, in
interface and in naming of the functions...)

[Note:
it's really just a guess; I *refused* to study them]

>> > The header to include is --just guess-- <string> itself (and not
>> > <stdio.h> or <sprintf> :-)), which someone must have deemed not
>> > crowded enough, either.
>
> The header is <string>. Which is a little crowded, but mainly
> crowded with the definition of std::basic_string itself, which
> has a somewhat bloated interface.

99% of the standard headers are more than "a little crowded". In
general, it's the "partitioning" that is a disaster (in the case
of <string>, of course, the bloated interface does its part, and
the templating, and...).

Let me start from elsewhere; say I want to write this incredibly
simple incantation, where 'in' is an istream:

in.rdbuf()->sgetc() == EOF // [1]

Question: what includes do I need for it? Well, at least the
following:

- <istream> (duh)
- <streambuf> (we're calling the sgetc member)
- <stdio.h> or <cstdio> (we are using the macro EOF)

(sgetc() may return the value of EOF --if your library
implementor is in a "I'm practical and I'll hardcode it...
this is as likely to change as the number of days in a
week"-mood, the standard authorizes him to just write e.g.
"return -1 ;")

But, heck, I'm using the wonderful C++ iostreams, not stdio!

So, let's try a variation:

typedef ... traits_type ;
in.rdbuf()->sgetc() == traits_type::eof() ;

Lovely. Now what do I need to include? Well, we are calling a
member of the corresponding traits_type, so we need it's
definition. Where is it? Tadaa... it's in <string>! But I just
wanted to see if my stream has another character for me or not.
What do strings have to do with that? And what the heck does the
notion of "eof" have to do with strings, or even with *char*
traits???

<aside>
This is one of the reasons why I often put simple things as [1]
in their own function, implemented in a separate source file:
because they need a crazy, absolutely counter-intuitive, bunch
of #includes which --if simply added where [1] is needed--would
just confuse the list of #includes: say, e.g., a future
maintainer notice that I'm not using std::string and drops the
#include <string>. Is he really to blame? Should have he noticed
that I'm using traits_type::? (Note that it's not even an
explicit char_traits< char >.)
<aside>


Now, the to_string functions mentioned above are specified in
terms of sprintf, which is in <stdio.h>/<cstdio>. So, the most
likely thing is that the implementor will simply include one of
those from within <string> itself. At most, he could include "a
part of it" (just to understand each other: having something
like a bits/ sub-directory). More than that is asking for
trouble: if you replace sprintf with something else you have to
prove the non-violation of the wonderful "as if rule": an
exercise in "mathematics without axioms" that may get you to
prove anything and the contrary of anything, and which will get
*you* (the implementor) into trouble and the committee off the
hook---you showed exactly one of the subtle differences that may
exist between using sprintf and something else).

So, chances are that, by including <string> in the above, I also
get the definition of EOF. And stdio. Uh. Now think of the
various std::string overloads added here and there in the
library (fstream, etc.): these make all points where <string>
gets potentially included. See the chain? At this point I wonder
why there are "separate" headers at all and they don't just
switch to a unique <std_bloat>, perhaps pre-included by the
compiler.

> Once you've got the class
> definition, the added free functions are quite reasonable
> (although one might argue that the IO functions belong in
> a separate file).

Well, if one of the few C++'ers illuminated on software
engineering issues agrees with this I'm hopeless. Anyway:

I don't think that they are reasonable, wherever you put them.
It's the old issue of lexical_cast; I thought it was ascertained
that conversions from and to string are almost always formatting
and should be done via the C++ idioms for formatting (I learned
this from *you*). For a gazillions of reasons.

But I see the old argument of "helping novices" kicking in.
Yeah, nice try. Now we'll have entire new generations of them
asking why std::cout << value and std::cout << to_string( value)
don't give the same result.

(Honestly, given C++'s complexity --either "intrinsic" (given
the design goals) and due to a crazy tendency to complication
that the committee has-- anything you might do for novices is
just a drop in the ocean.)

--
Gennaro Prota | name.surname yahoo.com
Breeze C++ (preview): <https://sourceforge.net/projects/breeze/>
Do you need expertise in C++? I'm available.

[ comp.std.c++ is moderated. To submit articles, try just posting with ]

Seungbeom Kim

unread,
Aug 26, 2010, 3:09:03 PM8/26/10
to
On 2010-07-10 00:56, James Kanze wrote:
>
> The standard definition does, however, show one of the reason
> why defining such functions is problematic. After implementing
> the standard specification for double and calling it on 1E40 and
> 1E-40, I get:
>
> as string: "10000000000000000303786028427003666890752.000000"
> as string: "0.000000"
>
> Neither are really useful output. (The default formatting for
> std::ostream might be more generally useful, but until you know
> more context, you can't really decide. For debugging, for
> example, I'd prefer that the precision was increased.)

I really wonder why "%[L]f" was chosen for floating-point numbers,
instead of "%[L]g". Where can I find the rationale?

Isn't "%g" supposed to be the *default* format, since it automatically
chooses between fixed-point or scientific? It will do "the correct
thing" for a far wider range of values. That's why the floating-point
conversion by streams in their default state (when neither ios_base::
fixed or ios_base::scientific is set) uses "%g", and hence the name
"defaultfloat".

The draft, as is now, presents a serious inconsistency:

const double v = 1e-40;

std::ostringstream os;
os << v;
std::string s = os.str(); // "1e-40"

std::string t = std::to_string(v); // "0.000000"

IMO, we should not allow such a gratuitous inconsistency.


On the other hand, it would also be better if they accepted optional
arguments for the style (g/f/e) and the precision, but one may think
this is too much and makes things too complicated...

>
> One also wonders why they didn't make it a template, so that
> user defined classes (which define a << operator) are
> automatically covered.

Maybe because that leads to a stream-based implementation, while
the proposal author wanted a stdio-based implementation?

--
Seungbeom Kim

0 new messages