[SoC][string_cvt] The proposal for string conversions library.

Hello, boost This is an idea of project for Google SoC2006 that I want to participate. The library is called 'string_cvt' – or “string conversions”, it solves the problem of converting type to string and string to type with minimal runtime and syntactical overhead. It is a simple "call for interest" mail. Idea for this lib was inspired by recent discussion on boost developers mailing list. The question under discussion was: Is lexical_cast<> tool good enough for TR2 or not? A proponents of lexical_cast<> have a point that the main advantage of lexical_cast<> component is its usage simplicity and symmetry (angle braces are used in both cases): int i = lexical_cast<int>("1"); string s = lexical_cast<string>(1); Additionally, it looks like built-in casts, and it is considered as a very cool thing. On the other side, opponents of lexical_cast<> wants more functionality that doesn't fit into simple cast-like usage like: The requirements table. 1) controlling conversions via facets (locales) 2) full power of iostreams in simple interface. All functionality accessible with iostreams (through manipulators) should be accessible. 3) functor adapters to use with std algorithms 4) error handling and reporting. (what kind of error occurred?) * optionally report failing without exceptions raising 5) best performance, especially for built-in types and for use in loops The "Lexical Conversion Library Proposal for TR2" by Kevlin Henney and Beman Dawes states, that: "The lexical_cast function template offers a convenient and consistent form for supporting common conversions to and from arbitrary types when they are represented as text. The simplification it offers is in expression-level convenience for such conversions. For more involved conversions, such as where precision or formatting need tighter control than is offered by the default behavior of lexical_cast, the conventional stringstream approach is recommended." It is clear that lexical_cast is not intended to address (1-4) points in the list above, and even (5). For optimizing conversions in loops you'll need to resort to stringstreams again. I believe, that stringstreams are not the right tool for daily string conversions job. We need a special and fully featured solution, which addresses all issues in the Requirements table above. My dream is that one has no need to fallback to C-style solutions or to stringstreams anymore, just one consistent interface for all string conversion needs. This proposal for Google SoC project is an attempt to develop such a solution. The final ambitious goal of this project is to make boost::lexical_cast<> obsolete and replace it in TR2 with a new proposal. Regardless of SoC, I’m going to develop such a library for boost, but the participation in the Google SoC is important because otherwise it would be hard to manage enough time to finish this library before the deadline for TR2 in October. As a result of this project we would have not only fully documented and tested library for string conversions, but full comparative performance analysis would be made to ensure that there is no more any need to fallback to some other solution. There are short examples of intended usage of this library (for those who are too busy to read the full proposal’s text) // simple initialization usage: string s = string_from(1); int i = from_string(“1”); // embedded in expression usage: double d = 2 + (double)from_string(“1”); // usage with special locale: string s = string_from(1, std::locale(“loc_name”)); // usage with special format: string s = string_from(1, std::ios::hex); // usage with special format and locale: string s = string_from(1, std::ios::hex, std::locale(“loc_name”)); // usage with default value provided (exceptions are not thrown): int i = from_string(“1”, 1); // usage with cvtstate& argument (exceptions are not thrown. if conversion fails, reason is written in the cvtstate parameter supplied): cvtstate state; int i = from_string(“1”, state); fmt and locale info can be supplied in from_string function too. To optimize conversions in a loop one can do: string_cvt cvt(std::ios::hex, std::locale(“loc_name”)); string s; for(int i; i < 100; ++i) { string t; cvt(i, t); s += (t + “ “); } To convert one sequence to another one can do: vector<double> vec_doubles(10, 1.2); vector<string> vec_strings; string_ocvt_fun<string> ocvtf(cvt); // cvt is defined in a previous example transform( vec_doubles.begin(), vec_doubles.end(), // from back_inserter(vec_strings), // to ocvtf ); // and in a reverse direction: string_icvt_fun<double> icvtf(scvt); vector<double> vec_doubles1(10); transform( vec_strings.begin(), vec_strings.end(), // from vec_doubles1.begin(), // to icvtf ); Details of this proposal are below: The proposal, part 1. from_string/(w)string_from functions. From syntactical point of view an alternative to lexical_cast<> approach was proposed: to_string/string_to<> pair of functions. The "Lexical Conversion Library Proposal for TR2" has a good argument against it: "... Furthermore, the from/to idea cannot be expressed in a simple and consistent form. The illusion is that they are easier than lexical_cast because of the name. This is theory. The practice is that the two forms, although similarly and symmetrically named, are not at all similar in use: one requires explicit provision of a template parameter and the other not. This is a simple usability pitfall that is guaranteed to catch experienced and inexperienced users alike -- the only difference being that the experienced user will know what to do with the error message." There is one more problem with this approach: to_string() function is coming from other languages like java, were it is a member function of all types, so one can wrote: String s = object.toString(); It can be spelled as: "Get string from object", or "Convert an object to string" Both phrases are straightforward and reflect the way that we think of it: 1) I want a string (String s = ) 2) I have an object (object) 3) I'm performing a conversion of this object to string (.toString()) But in C++ the to_string function would be a free-function, resulting in code like: string s = to_string(1); It can be spelled as: "Get string by converting an object '1' to string" The problem here is that the mental sequence is the same as in the example above, but language constructs doesn't reflect it: 1) I want a string (string s = ) 2) I have an object (1) 3) I'm performing a conversion of this object to string (to_string(1)) Note that (2) and (3) items are intermixed. It means, that programmer need to do some additional mental work to jump from item (1) to item (3) and then back to item (2) again. The final mind's workflow would be as follows: 1) I want a string (string s = ) 2) I have an object (1, but not code it, hold it in memory for a while) 3) I'm performing a conversion of this object to string (to_string) 4) Yes! I can release my memory, and code the object finally. ( (1); ) For such a widely used component as string conversions this additional complexity is inappropriate. Note: exactly the same critique can be addressed to lexical_cast<> too. And it has an additional complexity of explicitly specified template parameter. For string to type conversions all things are worse. in java it would be: try { int i = Integer.parseInt(s); // use i } catch (NumberFormatException) { /* perform some error handling or ignore - the usual practice */ } with lexical_cast<> it would be: int i = lexical_cast<int>(s); // use i // exception handling is usually done on a higher levels with string_to<> it would be: int i = string_to<int>(s); just a name was changed here. The resulting mental sequence for all 3 variants above is far from optimal. for lexical_cast<> it would be as follows: 1) I want an int (int i = ) 2) I have a string (s, but not code it, hold it in memory for a while) 3) I'm performing a conversion of this string to an int ( lexical_cast<int> ) 4) Yes! I can release my memory, and code the string finally. ( (s); ) The same mental complexity here. the shortest mental sequence possible is as follows: 1) I want an int (int i = ) 2) I have a string (s) 3) I'm performing a conversion of this string to an int ( toInt(); ) int i = s.toInt(); this approach scales bad, of cause, but it is optimal in a mental sense. Furthermore, one can mention that the best way would be as follows: int i = s; "Construct an int from a string" - as simple as it could be. Surprisingly, it can be implemented! (in terms of templated type cast operator): class string { template<typename T> operator T(); }; But this solution has major drawbacks: 1) it can not be made symmetrical with type to string conversion 2) it is hard to see such conversions in code 3) it requires changes in the standard strings library all three can be resolved with some free-function adapter like string_to, but with more appropriate naming: int i = from_string(s); its counterpart would become: string s = string_from(1); wstring s = wstring_from(1); Note: 1) usage is symmetrical 2) no explicit template parameters The from_string function has one minor drawback: it can not be used in expressions without explicit casting to the type desired: double d = 2.0 + from_string(s); // doesn't works double d = 2.0 + (double)from_string(s); // does But it can be seen as an advantage, because: 1) intention is clear and enforced by compiler (operator'+' ambiguity, or run-time exception if 2.0 becomes 2 and s looks like “1.1”) 2) mentally, the expression "(double)from_string(s)" is close to optimal, it can be thought of as: "Get double from string" - It is hard to imagine thinking path that is shorter and reflects intentions in a more straightforward way. To conclude: the pair of [w]string_from/from_string functions is proposed to compete lexical_cast<> function template for simple needs of converting some type to string or string to some type. Additionally, these functions are not restricted to pure cast-like syntax, and could accept parameters like locale, std::ios::fmtflags and boost::cvtstate (it is a part of this proposal) to address issues (1), (2), and (4) consequently. (see the Requirements table above) The proposal, part 2. converter objects and functor adapters. This part is intended to address issues (3) and (5). It can be achieved by providing templated "converter objects" along with typedefs for char and wchar_t: basic_string_icvt<char_type, traits_type, allocator_type>: string_icvt, wstring_icvt basic_string_ocvt<char_type, traits_type, allocator_type>: string_ocvt, wstring_ocvt basic_string_cvt<char_type, traits_type, allocator_type>: string_cvt, wstring_cvt usage can be: string_cvt scvt(ios_base::hex, locale("")); string s; scvt(12, s); int i; scvt(s, i); and functor adapters: basic_string_ocvt_fun<TCont> typedef basic_string_ocvt_fun<std::string> string_ocvt_fun; typedef basic_string_ocvt_fun<std::wstring> wstring_ocvt_fun; basic_string_icvt_fun<Target, TChar, Traits, TAlloc>; // template typedef template < typename Target, typename Traits = std::char_traits<char>, typename TAlloc = std::allocator<char>
class string_icvt_fun : public basic_string_icvt_fun<Target, char, Traits, TAlloc> // template typedef template < typename Target, typename Traits = std::char_traits<wchar_t>, typename TAlloc = std::allocator<wchar_t>
class wstring_icvt_fun: public basic_string_icvt_fun<Target, wchar_t, Traits, TAlloc> These classes can be used as follows: vector<double> vec_doubles(10, 1.2); vector<string> vec_strings; string_ocvt_fun<string> ocvtf(scvt); transform( vec_doubles.begin(), vec_doubles.end(), // from back_inserter(vec_strings), // to ocvtf ); string_icvt_fun<double> icvtf(scvt); vector<double> vec_doubles1(10); transform( vec_strings.begin(), vec_strings.end(), // from vec_doubles1.begin(), // to icvtf ); int sz = vec_doubles.size(); for (int i = 0; i < sz; ++i) { assert(vec_doubles[i] == vec_doubles1[i]); } And, finally, all power of iostreams can be achieved with this classes: std::ios_base::fmtflags could be specified as a parameter of all converter classes’ constructors to specify some special formatting. Additionally, all family of fmtflags related functions from std::ios_base and std::basic_ios<> are provided. width() and fill() bounties are also provided. (If I forgot to mention some function - it was not intentionally, all meaningful functions from iostreams base classes would be included) In order to satisfy requirement (1) std::locale object can be specified as a parameter of constructor, or as an argument to imbue() function. getloc() function is provided too. For requirement (4) type cvtstate is provided, that is very close to std::ios_base::iostate type, but cvtstate is not a typedef for int, to allow function overloads on it. ‘cvtstate except’ parameter can be provided to constructors of converter classes to specify cases when exceptions should be thrown. By default no exceptions are thrown. The state of conversion (successful or not) can be viewed with rdstate() function and all good/bad/fail functions. Additionally, exception handling behavior can be queried/changed with exceptions() functions. Again, exactly as in std::basic_ios class. Performance for built-in types (the requirement number 5) would be achieved in specializations of components proposed. These specializations would use the technique, proposed in n1803 document – “Simple Numeric Access”: strtoXXX() C-library functions to convert strings to numbers and sprintf() function to convert from numbers to strings. Support for non-standard strings can be done by specializing cvt_tarits<TCont> for them. Till now I have a minimal working implementation of basic concepts proposed. Possible mentors for this project could be authors of the “Lexical Conversion Library Proposal for TR2” proposal - Kevlin Henney and/or Beman Dawes. Best, PhD student, Oleg Abrosimov.

On Mon, 01 May 2006 10:25:48 +0700, Oleg Abrosimov wrote
Hello, boost
This is an idea of project for Google SoC2006 that I want to participate. The library is called 'string_cvt' or string conversions, it solves the problem of converting type to string and string to type with minimal runtime and syntactical overhead.
It is a simple "call for interest" mail.
Hi Oleg - Let me just say I believe there is a clear interest in this area, so I encourage you to submit an soc proposal. A few comments inline below:
Idea for this lib was inspired by recent discussion on boost developers mailing list. The question under discussion was: Is lexical_cast<> tool good enough for TR2 or not?
A proponents of lexical_cast<> have a point that the main advantage of lexical_cast<> component is its usage simplicity and symmetry (angle braces are used in both cases): int i = lexical_cast<int>("1"); string s = lexical_cast<string>(1);
Additionally, it looks like built-in casts, and it is considered as a very cool thing.
On the other side, opponents of lexical_cast<> wants more functionality that doesn't fit into simple cast-like usage like:
The requirements table. 1) controlling conversions via facets (locales) 2) full power of iostreams in simple interface. All functionality accessible with iostreams (through manipulators) should be accessible. 3) functor adapters to use with std algorithms 4) error handling and reporting. (what kind of error occurred?) * optionally report failing without exceptions raising 5) best performance, especially for built-in types and for use in loops
The "Lexical Conversion Library Proposal for TR2" by Kevlin Henney and Beman Dawes states, that: "The lexical_cast function template offers a convenient and consistent form for supporting common conversions to and from arbitrary types when they are represented as text. The simplification it offers is in expression-level convenience for such conversions. For more involved conversions, such as where precision or formatting need tighter control than is offered by the default behavior of lexical_cast, the conventional stringstream approach is recommended."
I presume this is n1973? http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1973.html
It is clear that lexical_cast is not intended to address (1-4) points in the list above, and even (5). For optimizing conversions in loops you'll need to resort to stringstreams again.
I believe, that stringstreams are not the right tool for daily string conversions job. We need a special and fully featured solution, which addresses all issues in the Requirements table above. My dream is that one has no need to fallback to C-style solutions or to stringstreams anymore, just one consistent interface for all string conversion needs. This proposal for Google SoC project is an attempt to develop such a solution. The final ambitious goal of this project is to make boost::lexical_cast<> obsolete and replace it in TR2 with a new proposal. Regardless of SoC, Im going to develop such a library for boost, but the participation in the Google SoC is important because otherwise it would be hard to manage enough time to finish this library before the deadline for TR2 in October.
One other proposal you should be aware of is Pete Becker's n1982 for simple numeric to string conversions: http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1982.html Part of the synopsis: int stoi(string& str, int base = 10); long stol(string& str, int base = 10); unsigned long stoul(string& str, int base = 10); long long stoll(string& str, int base = 10); unsigned long long stoull(string& str, int base = 10); float stof(string& str); double stod(string& str); long double stold(string& str); string to_string(long long val); string to_string(unsigned long long val); string to_string(long double val); //...snip more.... wstring to_wstring(long long val); wstring to_wstring(unsigned long long val); wstring to_wstring(long double val); While this is a very C like proposal it fills a basic gap in C++ for basic, high performance, (w)string to number conversions. My understanding is this the committee is pretty fond of this proposal -- perhaps someone that was in Berlin can say more (Beman, Howard?).
As a result of this project we would have not only fully documented and tested library for string conversions, but full comparative performance analysis would be made to ensure that there is no more any need to fallback to some other solution.
There are short examples of intended usage of this library (for those who are too busy to read the full proposals text)
// simple initialization usage: string s = string_from(1); int i = from_string(1);
// embedded in expression usage: double d = 2 + (double)from_string(1);
I think having a C-style cast is a no no. I assume: double d = 2 + static_cast<double>(from_string(1)); would work as well?
...snip lots of good details...
One thing I didn't see address in your proposal is how 'user defined types' can be handled. So, for example, with lexical cast I can do this: using namespace boost::gregorian; date d(2006,May, 1); std::string ds = lexical_cast<std::string>(d); and this std::string ds("2006-May-01"); date d = lexical_cast<date>(ds); This works because date has a defined operator<< and operator>>. You would need to show how this would be done in your proposal to really compete with lexical cast. Also note that with updates to the date-time global facet, the format of the date can be changed around, localized etc.
Till now I have a minimal working implementation of basic concepts proposed.
Possible mentors for this project could be authors of the Lexical Conversion Library Proposal for TR2 proposal - Kevlin Henney and/or Beman Dawes.
I'm not sure Kevlin or Beman is available, but I'm certain we can find a good mentor if the proposal is accepted. Jeff

"Jeff Garland" <jeff@crystalclearsoftware.com> wrote in message news:20060501040735.M23040@crystalclearsoftware.com...
... One other proposal you should be aware of is Pete Becker's n1982 for simple
numeric to string conversions:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1982.html
... While this is a very C like proposal it fills a basic gap in C++ for basic, high performance, (w)string to number conversions. My understanding is this the committee is pretty fond of this proposal -- perhaps someone that was in Berlin can say more (Beman, Howard?).
At least at the moment, the LWG intends to go forward with both proposals. I'm personally not convinced that is a good idea. Sounds a bit too much like design-by-committee. Time will tell.
...
Possible mentors for this project could be authors of the "Lexical Conversion Library Proposal for TR2" proposal - Kevlin Henney and/or Beman Dawes.
I'm not sure Kevlin or Beman is available, but I'm certain we can find a good mentor if the proposal is accepted.
I'm trying to focus this summer on moving Boost libraries into TR2, so am not signing up for mentoring. Kevlin is always overcommitted too. OTOH, it really would be helpful is someone looked at the entire conversion picture, and tried to synthesize a complete solution. --Beman

On Mon, 1 May 2006 08:05:52 -0400, Beman Dawes wrote
"Jeff Garland" <jeff@crystalclearsoftware.com> wrote in message news:20060501040735.M23040@crystalclearsoftware.com...
... One other proposal you should be aware of is Pete Becker's n1982 for simple
numeric to string conversions:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1982.html
... While this is a very C like proposal it fills a basic gap in C++ for basic, high performance, (w)string to number conversions. My understanding is this the committee is pretty fond of this proposal -- perhaps someone that was in Berlin can say more (Beman, Howard?).
At least at the moment, the LWG intends to go forward with both proposals. I'm personally not convinced that is a good idea. Sounds a bit too much like design-by-committee. Time will tell.
Has anyone considered the possibility that Pete's proposal might serve as the core for a more efficient lexical_cast? I guess internationalization / locale issues prevent that scenario?
Possible mentors for this project could be authors of the "Lexical Conversion Library Proposal for TR2" proposal - Kevlin Henney and/or Beman Dawes.
I'm not sure Kevlin or Beman is available, but I'm certain we can find a good mentor if the proposal is accepted.
I'm trying to focus this summer on moving Boost libraries into TR2, so am not signing up for mentoring. Kevlin is always overcommitted too.
Yep, that's what I figured.
OTOH, it really would be helpful is someone looked at the entire conversion picture, and tried to synthesize a complete solution.
I agree. And I presume you will want to make time to review any designs in this area even if it isn't officially mentoring? Jeff

Jeff Garland wrote:
Has anyone considered the possibility that Pete's proposal might serve as the core for a more efficient lexical_cast?
Are those functions implemented?
I guess internationalization / locale issues prevent that scenario?
As I pointed out in other thread, I implemented integral2str but it converts according to "C" locale. I'm going to add thousands_sep after every group of 3 digits for locales with appropriate grouping. I expect a slight performance degradation but it should be much faster then ostringstream anyway. As I don't know anything about locales with other grouping, I can't say how efficient integral2str might be for those locales. -- Alexander Nasonov Project Manager http://www.akmosoft.com

Alexander Nasonov wrote:
Jeff Garland wrote:
Has anyone considered the possibility that Pete's proposal might serve as the core for a more efficient lexical_cast?
Are those functions implemented?
I think Dinkumware has an implementation, but I'm not aware of an open implementation. Actually should be pretty trivial as dispatches to the low level C routines. Again as I understand that's the intent. Jeff

Jeff Garland wrote:
I think Dinkumware has an implementation, but I'm not aware of an open implementation. Actually should be pretty trivial as dispatches to the low level C routines. Again as I understand that's the intent.
I didn't consider this case for several reasons: 1. to avoid mixing of C and C++ locales 2. itoa is non-standard 3. sprintf is not fast enough ;-) Performance of sprintf is not a big issue especially if std::string ctor allocates a memory from the heap. Actually, instead of having a set of functions that returns std::string, I'd prefer std::tr1::array<char,N>. It's faster and you always know max. length of output. -- Alexander Nasonov Project Manager http://www.akmosoft.com

Jeff Garland:
One other proposal you should be aware of is Pete Becker's n1982 for simple numeric to string conversions:
http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2006/n1982.html
Thank you for pointing me to the newer version of this proposal. Till now I was aware of n1803 one.
// simple initialization usage: string s = string_from(1); int i = from_string(“1”);
// embedded in expression usage: double d = 2 + (double)from_string(“1”);
I think having a C-style cast is a no no. I assume:
double d = 2 + static_cast<double>(from_string(“1”));
would work as well?
yes, your version would work as well, but is too verbose ;-) the function from_string returns proxy object with templated cast to T operator defined. the purpose of explicit cast in the code above is to invoke the right cast operator. but I don't share the "no no" opinion against C-style cast in general. The Bjarne Stroustrup's book "The Design and Evolution of C++" has very good arguments in favor of this opinion: 1) They (C-style casts) are hard to understand because mix different meanings (static_cast/const_cast/reinterpret_cast) in one laguage construct; 2) provoke mistakes because of close to any combination of types have some legal meaning; // personally, I don't really understand what he mean by that :-( 3) it is hard to find them in code by eyes or by utilities like grep; 4) it complicates C and C++ grammar. now consider the code snippet again: double d = 2 + (double)from_string(“1”); 1) is it hard to understand what is going on here? from first glance? after explanation? 2) ??? 3) is it hard to find such constructs in code? {grep from_string} would help. 4) C-style casts won't disappear in any observable time because of interoperability with C. to conclude, I understand reasons against C-style cast in C++ and actually I don't remember when I've used it last time, but in this particular case I can not see any application of these reasons. I believe that in the case of "(double)from_string(“1”);" construct these reasons are just wrong. fill free to correct me, if I miss something. I like the "(double)from_string(“1”)" construct because it clearly says what is going on, it can be directly translated to: get double from string "1". Attractive! Isn't it?
One thing I didn't see address in your proposal is how 'user defined types' can be handled. So, for example, with lexical cast I can do this:
using namespace boost::gregorian; date d(2006,May, 1); std::string ds = lexical_cast<std::string>(d);
and this
std::string ds("2006-May-01"); date d = lexical_cast<date>(ds);
This works because date has a defined operator<< and operator>>. You would need to show how this would be done in your proposal to really compete with lexical cast. Also note that with updates to the date-time global facet, the format of the date can be changed around, localized etc.
Of cause, you are right! The library proposed is a simple wrapper around std::iostreams and C-library functions, mentioned in n1982 proposal. It means that all functionality of iostreams (including UDT to string and vice versa conversions) are allowed (and encouraged, of cause). with the library proposed one can rewrote your example in the following way: using namespace boost::gregorian; date d(2006,May, 1); std::string ds = string_from(d); and this std::string ds("2006-May-01"); date d = from_string(ds); simple and symmetric.
Till now I have a minimal working implementation of basic concepts proposed.
Possible mentors for this project could be authors of the “Lexical Conversion Library Proposal for TR2” proposal - Kevlin Henney and/or Beman Dawes.
I'm not sure Kevlin or Beman is available, but I'm certain we can find a good mentor if the proposal is accepted.
hope so Oleg Abrosimov.

On 5/2/06, Oleg Abrosimov <beholder@gorodok.net> wrote:
now consider the code snippet again: double d = 2 + (double)from_string("1");
1) is it hard to understand what is going on here? from first glance? after explanation? 2) ??? 3) is it hard to find such constructs in code? {grep from_string} would help. 4) C-style casts won't disappear in any observable time because of interoperability with C.
Mightn't this be better-spelled as: double d = 2 + from_string<double> ("1"); This is exactly as many characters as the C-style cast version, but much more in keeping with modern C++ style (IMHO of course). Is your idea that from_string would return a proxy object that supports e.g. operator double(), operator int(), etc? I think a templated function would be simpler and perhaps more optimal, and provide more opportunity for user-defined conversions. -- Caleb Epstein caleb dot epstein at gmail dot com

Oleg Abrosimov wrote:
Jeff Garland:
// embedded in expression usage: double d = 2 + (double)from_string(“1”); I think having a C-style cast is a no no. I assume:
double d = 2 + static_cast<double>(from_string(“1”));
would work as well?
yes, your version would work as well, but is too verbose ;-) the function from_string returns proxy object with templated cast to T operator defined. the purpose of explicit cast in the code above is to invoke the right cast operator.
That's what I thought, but given c-style cast I wasn't entirely sure.
but I don't share the "no no" opinion against C-style cast in general. ...snip cast no-no details...
now consider the code snippet again: double d = 2 + (double)from_string(“1”);
1) is it hard to understand what is going on here? from first glance? after explanation?
Yeah, well I'm always a bit unsure when the 'c-big-nasty-beat-it-with-a-hammer-cast' is used. I'm thinking I want to read/run the code just in case from_string returns a pointer and the compiler adds the pointer to 2 giving me some wacko result.
4) C-style casts won't disappear in any observable time because of interoperability with C.
Well, they especially won't disappear if folks who know better (that's you) perpetuate them. Not very many C++ programmers fully understand the implications of the c-cast (me included). In my experience casting leads to more casting -- programmers that don't understand what they are doing copy the bad code. It's like a fungus on a piece of code. Sure you can abuse new style casts, but it takes more time. You have to rethink why you are casting in the first place...
to conclude, I understand reasons against C-style cast in C++ and actually I don't remember when I've used it last time, but in this particular case I can not see any application of these reasons. I believe that in the case of "(double)from_string(“1”);" construct these reasons are just wrong.
fill free to correct me, if I miss something.
I really think if you really plan to produce something that goes to the standard committee you ought to drop the C and stick to C++. Maybe I'm wrong, but I'm betting alot of C++ folks will have the same reaction as me.
I like the "(double)from_string(“1”)" construct because it clearly says what is going on, it can be directly translated to: get double from string "1". Attractive! Isn't it?
Nope. Well I'm afraid that I see one serious problem with this idea that lexical cast avoids -- ambiguity. The following code will not compile on g++ 3.3.2 -- totally bogus implementations, but just to give you the idea: //test.cpp #include <iostream> double from_string(std::string s) { static double d = 10.2; return d; } int from_string(std::string s) { static int i = 10; return i; } using namespace std; int main() { double d = 2 + (double)from_string("10.2"); std::cout << d << std::endl; return 0; } test.cpp:6: error: ambiguates old declaration `double from_string(... Basically, you can't overload on return type. Lexical cast gets around this for the obvious reasons. Anyway, I'm starting to wonder if this idea is feasible at all -- am I missing something?
One thing I didn't see address in your proposal is how 'user defined types' can be handled. So, for example, with lexical cast I can do this:
using namespace boost::gregorian; date d(2006,May, 1); std::string ds = lexical_cast<std::string>(d);
and this
std::string ds("2006-May-01"); date d = lexical_cast<date>(ds);
This works because date has a defined operator<< and operator>>. You would need to show how this would be done in your proposal to really compete with lexical cast. Also note that with updates to the date-time global facet, the format of the date can be changed around, localized etc.
Of cause, you are right! The library proposed is a simple wrapper around std::iostreams and C-library functions, mentioned in n1982 proposal. It means that all functionality of iostreams (including UDT to string and vice versa conversions) are allowed (and encouraged, of cause).
with the library proposed one can rewrote your example in the following way:
using namespace boost::gregorian; date d(2006,May, 1); std::string ds = string_from(d);
and this
std::string ds("2006-May-01"); date d = from_string(ds);
simple and symmetric.
Well, again, I'm not sure how you can make this work. The only way I know how is to make from_string a template function...so this is basically back to lexical cast, no? Jeff

Jeff Garland:
Yeah, well I'm always a bit unsure when the
'c-big-nasty-beat-it-with-a-hammer-cast' is used. I'm thinking I want to read/run the code just in case from_string returns a pointer and the compiler adds the pointer to 2 giving me some wacko result.
4) C-style casts won't disappear in any observable time because of
interoperability with C.
Well, they especially won't disappear if folks who know better
(that's you) perpetuate them. Not very many C++ programmers fully understand the implications of the c-cast (me included). In my experience casting leads to more casting -- programmers that don't understand what they are doing copy the bad code. It's like a fungus on a piece of code. Sure you can abuse new style casts, but it takes more time. You have to rethink why you are casting in the first place...
to conclude, I understand reasons against C-style cast in C++ and
fill free to correct me, if I miss something.
I really think if you really plan to produce something that goes to
actually I don't remember when I've used it last time, but in this particular case I can not see any application of these reasons. I believe that in the case of "(double)from_string(“1”);" construct these reasons are just wrong. the standard committee you ought to drop the C and stick to C++. Maybe I'm wrong, but I'm betting alot of C++ folks will have the same reaction as me.
I like the "(double)from_string(“1”)" construct because it clearly
says what is going on, it can be directly translated to: get double from string "1".
Attractive! Isn't it?
Nope.
Well I'm afraid that I see one serious problem with this idea that lexical cast avoids -- ambiguity. The following code will not compile on g++ 3.3.2 -- totally bogus implementations, but just to give you the idea: //test.cpp #include <iostream>
double from_string(std::string s) { static double d = 10.2; return d; }
int from_string(std::string s) { static int i = 10; return i; }
using namespace std;
int main() {
double d = 2 + (double)from_string("10.2"); std::cout << d << std::endl; return 0;
}
test.cpp:6: error: ambiguates old declaration `double from_string(...
Basically, you can't overload on return type. Lexical cast gets around this for the obvious reasons. Anyway, I'm starting to wonder if
Ok I see your point. It would be interesting though to make a polling on c.l.c++.m on this question just to see the whole picture. anyway, usage of C-style cast is not required. for simple initialization one can do: double d = from_string("10.2"); and if one has a real need to use it in a complex expression: double d = 2 + static_cast<double>(from_string("10.2")); or, better: double d = from_string("10.2"); d += 2; and if one wants to be very modern ;-) but doesn't concern about symmetry in from_string/string_from usage : double d = 2 + from_string<double>("10.2"); it could be supported in parallel with non-templated version. (see code below) this idea is feasible at all -- am I missing something? see below
with the library proposed one can rewrote your example in the
following way:
using namespace boost::gregorian; date d(2006,May, 1); std::string ds = string_from(d);
and this
std::string ds("2006-May-01"); date d = from_string(ds);
simple and symmetric.
Well, again, I'm not sure how you can make this work. The only way I know how is to make from_string a template function...so this is basically back to lexical cast, no?
no, try the following code: #include <iostream> #include <sstream> struct fs_helper { fs_helper(std::string const& s) : m_str(s) {} template <typename T> operator T() { std::stringstream ss(m_str); T t; ss >> t; return t; } private : std::string m_str; }; inline fs_helper from_string(std::string const& str) { return fs_helper(str); } template <typename T> inline T from_string(std::string const& str) { return static_cast<T>(fs_helper(str)); } int main() { double d0 = from_string("10.2"); double d = 2 + (double)from_string("10.2"); double d2 = 4 + from_string<double>("10.2"); std::cout << d0 << std::endl; std::cout << d << std::endl; std::cout << d2 << std::endl; return 0; } it perfectly works on VC7.1 at least. and compiles by Comeau C/C++ 4.3.3 (Aug 6 2003 15:13:37) for ONLINE_EVALUATION_BETA1 Copyright 1988-2003 Comeau Computing. All rights reserved. MODE:strict errors C++ In strict mode, with -tused, Compile succeeded. Best, Oleg Abrosimov.

Oleg Abrosimov wrote:
Jeff Garland:
Ok I see your point. It would be interesting though to make a polling on c.l.c++.m on this question just to see the whole picture.
Be my guest, but I think you have it right below.
anyway, usage of C-style cast is not required. for simple initialization one can do: double d = from_string("10.2");
and if one has a real need to use it in a complex expression: double d = 2 + static_cast<double>(from_string("10.2"));
or, better:
double d = from_string("10.2"); d += 2;
Honestly, this is more like it anyway -- trivial way to avoid all the casts -- not doubts at all what the code does. No casting fungus to start growing ;-)
and if one wants to be very modern ;-) but doesn't concern about symmetry in from_string/string_from usage : double d = 2 + from_string<double>("10.2");
This is fine too. Perfect symmetry isn't really needed.
it could be supported in parallel with non-templated version. (see code below)
Well I'm afraid that I see one serious problem with this idea that lexical cast avoids -- ambiguity. The following code will not compile on g++ 3.3.2 -- totally bogus implementations, but just to give you the idea:
...snip jeff's code... no, try the following code:
#include <iostream> #include <sstream>
struct fs_helper { fs_helper(std::string const& s) : m_str(s) {} template <typename T> operator T() { std::stringstream ss(m_str); T t; ss >> t; return t; }
private : std::string m_str; };
inline fs_helper from_string(std::string const& str) { return fs_helper(str); }
template <typename T> inline T from_string(std::string const& str) { return static_cast<T>(fs_helper(str)); }
int main() { double d0 = from_string("10.2"); double d = 2 + (double)from_string("10.2"); double d2 = 4 + from_string<double>("10.2"); std::cout << d0 << std::endl; std::cout << d << std::endl; std::cout << d2 << std::endl; return 0; }
it perfectly works on VC7.1 at least. and compiles by
Sure, this is fine -- as I said, the only way I could see it working was as a template function -- which wasn't entirely obvious from your earlier posts. But in the end, I fail to see how it really differs significantly from lexical_cast. They are both template function interfaces. Yes, I like the names better than lexical_cast. It is less generic, but by the time you are done you will need exceptions and templatization on string types -- all elements of lexical cast. In the base implementation you still have all the stringstream performance issues that people complain about with lexical_cast. I assume the idea is to specialize the common cases so they are faster than the stringstream implementation? Of course this could be done with lexical_cast -- it's been discussed many times and is not precluded by the Henney/Dawes proposal. In fact, I expect it's assumed that vendors would do better than Boost has so far. Let me wrap up by saying I'm not trying to discourage you -- just trying to make sure a realistic expectation / comparison is done upfront. Jeff

Jeff Garland wrote:
Oleg Abrosimov wrote:
and if one wants to be very modern ;-) but doesn't concern about symmetry in from_string/string_from usage : double d = 2 + from_string<double>("10.2");
This is fine too. Perfect symmetry isn't really needed.
I agree with Jeff. The string_from differs from the from_string in a fundamenal way: the former _accepts_ arguments of different types while the latter _returns_ different types. You can't overload on return types in C++. Why do you require a symmetry for asymmetrical functions? -- Alexander Nasonov Project Manager http://www.akmosoft.com

Alexander Nasonov:
Jeff Garland wrote:
Oleg Abrosimov wrote:
and if one wants to be very modern ;-) but doesn't concern about symmetry in from_string/string_from usage : double d = 2 + from_string<double>("10.2"); This is fine too. Perfect symmetry isn't really needed.
I agree with Jeff. The string_from differs from the from_string in a fundamenal way: the former _accepts_ arguments of different types while the latter _returns_ different types. You can't overload on return types in C++. Why do you require a symmetry for asymmetrical functions?
in the "Lexical Conversion Library Proposal for TR2" (N1973) proposal Kevlin Henney and Beman Dawes states: "Since either the source or target are usually strings, why not provide separate to_string(x) and string_to<t>(x) functions? The source or target isn't always a string. Furthermore, the from/to idea cannot be expressed in a simple and consistent form. The illusion is that they are easier than lexical_cast because of the name. This is theory. The practice is that the two forms, although similarly and symmetrically named, are not at all similar in use: one requires explicit provision of a template parameter and the other not. This is a simple usability pitfall that is guaranteed to catch experienced and inexperienced users alike -- the only difference being that the experienced user will know what to do with the error message." for me it is reasonable enough to require a symmetric usage of from_string/string_from functions I've proposed. Best, Oleg Abrosimov.

Oleg Abrosimov wrote:
Alexander Nasonov:
in the "Lexical Conversion Library Proposal for TR2" (N1973) proposal Kevlin Henney and Beman Dawes states:
"Since either the source or target are usually strings, why not provide separate to_string(x) and string_to<t>(x) functions?
The source or target isn't always a string. Furthermore, the from/to idea cannot be expressed in a simple and consistent form. The illusion is that they are easier than lexical_cast because of the name. This is theory. The practice is that the two forms, although similarly and symmetrically named, are not at all similar in use: one requires explicit provision of a template parameter and the other not. This is a simple usability pitfall that is guaranteed to catch experienced and inexperienced users alike -- the only difference being that the experienced user will know what to do with the error message."
for me it is reasonable enough to require a symmetric usage of from_string/string_from functions I've proposed.
Well, I can buy into the idea that the target is always a 'string'. And frankly I've never used any other sort of target/source for these kinds of conversion. But your're still not responding to the core of my question. The problem is "what's a string"? Some possibilities: std::wstring std::string std::basic_string<uchar> //some sort of unicode string std::vector<char> //and variants thereof sti::rope jeffs_really_cool_string_class // ;-) I think even if the plan is to limit to 'a string' you will need to support these sort of options. Which means you need a second templat argument. Which probably means you need to clearly define the concept of a string w.r.t these conversions. And perhaps that's how it differentiates from lexical_cast. That is lexical_cast requires Target == InputStreamable, DefaultConstructable and Source == OutputStreamable. What are your concept requirements? Jeff

Jeff Garland wrote:
Well, I can buy into the idea that the target is always a 'string'. And frankly I've never used any other sort of target/source for these kinds of conversion. But your're still not responding to the core of my question. The problem is "what's a string"? Some possibilities:
std::wstring std::string std::basic_string<uchar> //some sort of unicode string std::vector<char> //and variants thereof sti::rope jeffs_really_cool_string_class // ;-)
I think even if the plan is to limit to 'a string' you will need to support these sort of options. Which means you need a second templat argument.
Which probably means you need to clearly define the concept of a string w.r.t these conversions. And perhaps that's how it differentiates from lexical_cast. That is lexical_cast requires Target == InputStreamable, DefaultConstructable and Source == OutputStreamable. What are your concept requirements?
Jeff, I didn't respond to your previous mail where you request a detailed comparison between string_cvt and lexical_cast<> because it is a serious time investment that I can not manage for now (I'm really busy with my PhD work till the end of may). If you are really interested in this question and can not wait till June, you can jump into my the very first message in this thread. I believe, that all information is hidden ;-) in the above mentioned text. Additionally, in the end of this message, I've attached a copy of the project-related part of my SoC proposal text. If we speak about different types of strings, that all should be supported in some way, it is supported by design of string_cvt library. std::basic_string<> and any other sequence, that fulfills the Container requirement would be supported out of the box (except top-level wrappers like (w)string_from). And any other string/container of chars could be supported by specializing the cvt_traits template and providing simple functions like qtstring_from() with trivial implementation forwarding to basic_string_from<string_type>(). Details are below: till now support for string types other then std::basic_string<> was done through cvt_traits template: // it can be overriden for user-defined strings to support them template <typename TCont> struct cvt_traits { typedef typename TCont::value_type char_type; typedef typename TCont::traits_type traits_type; typedef typename TCont::allocator_type allocator_type; static const char_type* const c_str_from(TCont const& s) { return s.c_str(); } static TCont from_c_str(const char_type* const cs) { return TCont(cs); } }; and basic_string_from function template: template <typename TCont, typename T> inline TCont basic_string_from( T const& t [optional parameters, like std::ios_base::fmtflags and std::locale] ); it was used to implement (w)string_from function: template <typename T> inline std::(w)string (w)string_from( T const& t, std::ios_base::fmtflags flags = std::ios_base::dec, std::locale const& loc = std::locale::classic() ) { return basic_string_from<std::(w)string>(t, flags, loc); } and it can be used to implement conversion to jeffs_really_cool_string_class: template <typename T> inline jeffs_really_cool_string_class jeffs_really_cool_string_class_from( T const& t, std::ios_base::fmtflags flags = std::ios_base::dec, std::locale const& loc = std::locale::classic() ) { return basic_string_from<jeffs_really_cool_string_class>(t, flags, loc); } given that cvt_traits are specialized for it. But now, after discussion with Alexander Nasonov about string_from() realization for boost::array<> struct, I've realized, that it would be more efficient to utilize boost::iostreams library by Jonathan Turkanis. till now the very internal implementation looks like: template <typename T, typename TCont> void operator() (T const& t, TCont& s) { stream << t; string_type str = stream.str(); // temporary std::basic_string<> is created here s = cvt_traits<TCont>::from_c_str(str.c_str()); } it is suboptimal because temporary string object is created. string_convert library by Martin Adrian use special stream type with access to it's internal character buffer. but it is not optimal too, because additional copying from internal buffer is required. (if I understand it correctly) If I'm not missing something, with use of boost::iostreams it can be improved. for std::basic_string<>, boost::array<>, std::vector<> or any other container (in STL sense) cvt_traits template can be defined as: // it can be overriden for user-defined strings to support them template <typename TCont> struct cvt_traits { typedef typename TCont::value_type char_type; // it can be redundant because of char_type typedef in container_source/sink. typedef typename TCont::traits_type traits_type; typedef typename TCont::allocator_type allocator_type; typedef container_source<TCont> source_type; typedef container_sink<TCont> sink_type; }; where container_source/container_sink are defined as in boost::iostreams tutorial. with use of this new traits the internal conversion code would become: template <typename T, typename TCont> void operator() (T const& t, TCont& s) { boost::iostreams::stream<typename cvt_traits<TCont>::sink_type> stream(s); stream << t; } 1) I believe that it is optimal for performance 2) by providing appropriate specialization of cvt_traits one can enable string_cvt library for any string_type. Text of my SoC proposal is below: In current C++ standard there is no simple way to do string to type and type to string conversions. With use of std::iostreams conversion from some object to string would looks like: std::stringstream ss; ss << object; std::string s = ss.str(); That is too heavy compared to simple: String s = object.toString(); in java language, for example. At the same time, these conversions are made on a daily basis by most of C++ programmers. The reason is simple: most users’ input is a string that should be interpreted as an object of some type, and most program output is a text in some form, produced from objects. Two proposals were made to standards committee to solve this usability problem for “occasional” users (in terms of Bjarne Stroustrup): n1803 (Simple Numeric Access) and n1973 (Lexical Conversion Library Proposal for TR2). Both of these proposals failed to provide a consistent and extendable string conversions solution for C++ users. “Consistent” here means that there is no more any need to fallback to low-level C-library routines to achieve better performance or to std::iostreams to achieve better control over formatting or locale handling. Furthermore, having two different tools to achieve the same goal would be misleading for most of “occasional” C++ users. *** This project is targeted to solve the whole string conversion problem for C++ with minimal runtime and syntactical overhead in a form of a library wrapper around existing C++ library facilities like std::iostreams and C-library subset recommended in n1803 proposal. This library would be implemented as a boost library. After approval by boost community, a proposal for TR2 will be made to replace n1803 and n1973 proposals and to push the library developed in a future version of C++ standard. Below is a requirements list for string conversion components of the library proposed (these requirements were collected from boost developers’ critiques of n1973 proposal and from the n1973 proposal itself): 0) symmetrical approach for type to string and string to type conversions; 1) low syntactical overhead (short, but self-descriptive) 2) conversions could be controlled via facets (locales); 3) full power of iostreams in simple interface. All functionality accessible with iostreams (through manipulators) should be accessible; 4) functor adapters to use with std algorithms; 5) error handling and reporting. (what kind of error occurred?) * optionally report failing without exceptions raising; 6) performance comparable to low-level “C” constructs (for built-in types); 7) ability to tune performance when use in loops; *** As a result of this project the C++ community would have: 1) fully documented and tested library for string conversions under boost umbrella; 2) full comparative performance analysis would be made to ensure that there is no more any need to fallback to low-level C-library functions to achieve more performance; 3) a new proposal for C++ standards committee for TR2 (deadline in October 2006). *** The project timeline would be: June) Developing the library; July) Writing docs and full test suit. Test and tune performance. August) Pushing it through boost review process. Address issues if raised. Prepare proposal for TR2.

Oleg Abrosimov wrote:
[ ... skiped ... ] A proponents of lexical_cast<> have a point that the main advantage of lexical_cast<> component is its usage simplicity and symmetry (angle braces are used in both cases): int i = lexical_cast<int>("1"); string s = lexical_cast<string>(1);
Additionally, it looks like built-in casts, and it is considered as a very cool thing.
That's right.
On the other side, opponents of lexical_cast<> wants more functionality that doesn't fit into simple cast-like usage like:
The requirements table. 1) controlling conversions via facets (locales) 2) full power of iostreams in simple interface. All functionality accessible with iostreams (through manipulators) should be accessible.
For to_string functionality, you can use Boost.Format.
3) functor adapters to use with std algorithms I agree, that's a nice feature. May be we could try to add lambda support to it? Something like this: lexical_cast<_1>(_2);
4) error handling and reporting. (what kind of error occurred?) * optionally report failing without exceptions raising 5) best performance, especially for built-in types and for use in loops
I think that lexical_cast's performance can be improved. Yesterday I wrote a first version of integral2str which is several times faster then sprintf("%d"). It doesn't add thousands_sep to output but this can be easily changed (assuming that there are 3 digits in a group). I also like this idea: lexical_cast< boost::array<char, 30> >(INT_MIN); Unlike builtin arrays, boost::array can be copied and therefore, it can be returned from a function. We could get rid of dynamic allocations for integral and other common types completely. It doesn't meet InputStreamable requirements, though.
[ ... skiped ... ] It is clear that lexical_cast is not intended to address (1-4) points in the list above, and even (5). For optimizing conversions in loops you'll need to resort to stringstreams again.
I don't think that stringstreams are the fastest.
[ ... skiped ... ] There are short examples of intended usage of this library (for those who are too busy to read the full proposal?s text)
// simple initialization usage: string s = string_from(1); int i = from_string(?1?);
// embedded in expression usage: double d = 2 + (double)from_string(?1?);
lexical_cast can do this.
// usage with special locale: string s = string_from(1, std::locale(?loc_name?));
// usage with special format: string s = string_from(1, std::ios::hex);
// usage with special format and locale: string s = string_from(1, std::ios::hex, std::locale(?loc_name?));
Use Boost.Format.
[ ... skiped ... ]
To optimize conversions in a loop one can do: string_cvt cvt(std::ios::hex, std::locale(?loc_name?)); string s; for(int i; i < 100; ++i) { string t; cvt(i, t); s += (t + ? ?); }
How use of cvt differs from ostringstream? std::ostringstream cvt; for(int i; i < 100; ++i) cvt << std::hex << i; std::string s = cvt.str();
Details of this proposal are below: [ ... skiped ... ] int i = from_string(s);
its counterpart would become: string s = string_from(1); wstring s = wstring_from(1);
Note: 1) usage is symmetrical 2) no explicit template parameters
The from_string function has one minor drawback: it can not be used in expressions without explicit casting to the type desired:
double d = 2.0 + from_string(s); // doesn't works double d = 2.0 + (double)from_string(s); // does
But it can be seen as an advantage, because: 1) intention is clear and enforced by compiler (operator'+' ambiguity, or run-time exception if 2.0 becomes 2 and s looks like ?1.1?) 2) mentally, the expression "(double)from_string(s)" is close to optimal, it can be thought of as: "Get double from string" - It is hard to imagine thinking path that is shorter and reflects intentions in a more straightforward way.
Disadvantages: 1) Reminds programmers of old-style casts. 2) Raise eyebrows of experienced programmers (what is a return type of from_string?) 3) Some coding standards prohibit old-style casts. Your example should be rewritten to satisfy those standards: double d = 2.0 + static_cast<double>(from_string(s)); It's worse then from_string<double>(s).
[ ... skiped ... ]
-- Alexander Nasonov Project Manager http://www.akmosoft.com

Alexander Nasonov:
For to_string functionality, you can use Boost.Format.
cool! but useless ;-( try to replace examples provided in my original message with boost::format and ask boosters if they want to use it for daily task of string conversions. anyway, the main goal of the library proposed is to provide a _consistent_ interface for string conversion purposes. The solution where a number of different and non-coherent components are used to accomplish logically closely related tasks is _very_ misleading.
3) functor adapters to use with std algorithms I agree, that's a nice feature. May be we could try to add lambda support to it? Something like this: lexical_cast<_1>(_2);
too cool too ;-)
4) error handling and reporting. (what kind of error occurred?) * optionally report failing without exceptions raising 5) best performance, especially for built-in types and for use in loops
I think that lexical_cast's performance can be improved. Yesterday I wrote a first version of integral2str which is several times faster then sprintf("%d"). It doesn't add thousands_sep to output but this can be easily changed (assuming that there are 3 digits in a group).
The purpose of the library proposed is to be a simple wrapper around existing C++ library facilities like iostreams. It doesn't invent new IO facilities, just provides one simple and consistent interface for string conversion purposes. If you succeed with your experiments, your code could be incorporated in string_cvt implementation details to improve performance in special cases.
I also like this idea:
lexical_cast< boost::array<char, 30> >(INT_MIN);
Unlike builtin arrays, boost::array can be copied and therefore, it can be returned from a function. We could get rid of dynamic allocations for integral and other common types completely. It doesn't meet InputStreamable requirements, though.
The string_cvt library is not rigidly bound to std::basic_string<> template. The library could be extended to work with any other string and even nonstring type, like boost::array<>. and it is not required to be InputStreamable, it should provide an appropriate specialization of cvt_traits<> template: // it can be overriden for user-defined strings to support them template <typename TCont> struct cvt_traits { typedef typename TCont::value_type char_type; typedef typename TCont::traits_type traits_type; typedef typename TCont::allocator_type allocator_type; static const char_type* const c_str_from(TCont const& s) { return s.c_str(); } static TCont from_c_str(const char_type* const cs) { return TCont(cs); } }; actually, it would be helpful to implement at least experimental support for such an array object to see if the interface of cvt_traits could be improved to allow specializations for such types perform faster.
[ ... skiped ... ] It is clear that lexical_cast is not intended to address (1-4) points in the list above, and even (5). For optimizing conversions in loops you'll need to resort to stringstreams again.
I don't think that stringstreams are the fastest.
yes, but given an object of type T with no accessors but only operators << and >> provided the only way would be to use iostreams in some form.
[ ... skiped ... ] There are short examples of intended usage of this library (for those who are too busy to read the full proposal?s text)
// simple initialization usage: string s = string_from(1); int i = from_string(?1?);
// embedded in expression usage: double d = 2 + (double)from_string(?1?);
lexical_cast can do this.
exactly!
To optimize conversions in a loop one can do: string_cvt cvt(std::ios::hex, std::locale(?loc_name?)); string s; for(int i; i < 100; ++i) { string t; cvt(i, t); s += (t + ? ?); }
How use of cvt differs from ostringstream?
std::ostringstream cvt; for(int i; i < 100; ++i) cvt << std::hex << i; std::string s = cvt.str();
Really good question! There is one major difference: string_cvt is a wrapper not only around iostreams, but around low-level C-library functions as well. That is why for conversions of built-in types (as in this simple example) iostreams machinery wouldn't be involved. As a result, code with "string_cvt" would perform faster at no cost for programmer. But the real difference is in separation of streaming and conversion concepts. It is a "good thing" to use streaming syntax for real streaming purposes and conversion syntax for conversion purposes. It gives a clue for those who would read your code later. To conclude, it improves maintainability.
double d = 2.0 + from_string(s); // doesn't works double d = 2.0 + (double)from_string(s); // does
Disadvantages:
1) Reminds programmers of old-style casts. 2) Raise eyebrows of experienced programmers (what is a return type of from_string?)
see another post in this topic for my view on C-style cast (not old-style, please).
3) Some coding standards prohibit old-style casts. Your example should be rewritten to satisfy those standards:
double d = 2.0 + static_cast<double>(from_string(s));
coding standards are important. to satisfy with them one can rewrote this as: double d = 2.0 + static_cast<double>(from_string(s)); or as: double d = from_string(s); d += 2.0;
It's worse then from_string<double>(s).
0) see other post for my opinion about C-style cast in this case 1) subjective 2) violates the symmetry principle of from_string/string_from functions, that is why is absolutely inappropriate. Thank you for your time investment in reading my original mail. Best, Oleg Abrosimov.

From: "Oleg Abrosimov" <beholder@gorodok.net>
Idea for this lib was inspired by recent discussion on boost developers mailing list. The question under discussion was: Is lexical_cast<> tool good enough for TR2 or not?
This discussion leaned in making one functional version in Boost Vault. It is placed as Strings - Text Processing / string_convert.zip. Is there any reason for starting developing entirely new library? Why not use it as a base? Best Regards, Tom

Tomas Pecholt:
From: "Oleg Abrosimov" <beholder@gorodok.net>
Idea for this lib was inspired by recent discussion on boost developers mailing list. The question under discussion was: Is lexical_cast<> tool good enough for TR2 or not?
This discussion leaned in making one functional version in Boost Vault. It is placed as Strings - Text Processing / string_convert.zip. Is there any reason for starting developing entirely new library? Why not use it as a base?
I'm aware of this library and I've seen into its internals. In fact, I've borrowed some useful ideas from it. But I'm afraid you just overestimate the value of the code of string_convert library itself. It is not a big deal to write some templates to encapsulate stream usage. I believe that the time investment to transforming the string_convert lib to string_cvt version I have right now would be approximately the same as to write string_cvt from scratch. The real big deal is to synthesize a solution that is complete and flexible enough. And this deal is not in coding itself, but in analyzing all issues that quickly arise here and there. anyway, I'm very lazy, so I'm going to reuse all available code around. and lexical_cast and string_convert are in my list, of cause ;-) Best, Oleg Abrosimov.
participants (6)
-
Alexander Nasonov
-
Beman Dawes
-
Caleb Epstein
-
Jeff Garland
-
Oleg Abrosimov
-
Tomas Pecholt