
It seems that I'm going in the same direction too, but with a little different approach. I belief it would be fruitful to merge our ideas and efforts, of cause. till now I have an interface specification and test code, but no implementation, so fill free to compile the .cpp file, but linking is not possible yet ;-) Oleg Abrosimov. // Copyright Oleg Abrosimov 2006. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // the test for proposal for type to string and // string to type conversions for C++ #include "scvt.hpp" using namespace boost; #include <iostream> #include <sstream> #include <vector> #include <algorithm> #include <cassert> using namespace std; // test all overloads of to_string function string test_ovl() { string str = to_string(12.3) + '\n' + to_string(12.3, locale("")) + '\n' + to_string(true, ios_base::boolalpha) + '\n' + to_string(12.3, ios_base::hex, locale("")) + '\n'; return str; } // test all overloads of to_string function wstring wtest_ovl() { wstring sendl; sendl += wcout.widen('\n'); wstring str = to_wstring(12.3) + sendl + to_wstring(12.3, locale("")) + sendl + to_wstring(true, ios_base::boolalpha) + sendl + to_wstring(12.3, ios_base::hex, locale("")) + sendl; return str; } // readability improvement test for to_string_cvt object template <typename TChar> basic_string<TChar> test_readabilty() { basic_ocvt<TChar> cvt(ios_base::hex, locale("")); basic_string<TChar> sendl; sendl = cvt.widen('\n'); basic_string<TChar> str = cvt(12.3) + sendl + cvt(12.4) + sendl + cvt(12.5) + sendl + cvt(12.6) + sendl + cvt(12.7) + sendl; return str; } // performance test for to_string_cvt object template <typename TChar> basic_string<TChar> test_performance() { basic_ocvt<TChar> cvt(ios_base::hex, locale("")); basic_string<TChar> sendl; sendl = cvt.widen('\n'); basic_string<TChar> str; for (int i = 0; i < 100; ++i) { str = cvt(i) + sendl; } return str; } // test functor functionality of to_string_cvt object template <typename TChar> basic_string<TChar> test_functor() { basic_ocvt<TChar> cvt(ios_base::hex, locale("")); vector<double> vec_doubles(10, 1.2); vector< basic_string<TChar> > vec_strings; transform( vec_doubles.begin(), vec_doubles.end(), // from back_inserter(vec_strings), // to cvt ); std::basic_ostringstream<TChar> os; basic_string<TChar> space; space += os.widen(' '); copy( vec_strings.begin(), vec_strings.end(), // from ostream_iterator<basic_string<TChar>, TChar>(os, space.c_str()) // to ); return os.str(); } template <typename TChar> basic_string<TChar> test_to_string() { basic_string<TChar> str = test_readabilty<TChar>() + test_performance<TChar>() + test_functor<TChar>(); return str; } // test all overloads of string_to function void test_ovl1() { string s("12.3"); double d = string_to<double>(s); assert(d == 12.3); } // test all overloads of to_string function void wtest_ovl1() { string s("12.3"); wstring ws(s.begin(), s.end()); double d = string_to<double>(ws); assert(d == 12.3); } // performance test for icvt object template <typename TChar> void test_performance1() { basic_icvt<TChar> cvt(ios_base::hex, locale("")); basic_icvt_functor<int, TChar> cvtf(cvt); string s("22"); basic_string<TChar> str(s.begin(), s.end()); for (int i = 0; i < 100; ++i) { int j = cvtf(str); int k; cvt(str, k); cvt(str, k, 0); } } // test functor functionality of basic_i(o)cvt objects template <typename TChar> void test_functor1() { basic_ocvt<TChar> cvt(ios_base::hex, locale("")); vector<double> vec_doubles(10, 1.2); vector< basic_string<TChar> > vec_strings; transform( vec_doubles.begin(), vec_doubles.end(), // from back_inserter(vec_strings), // to cvt ); basic_icvt<TChar> cvt1(ios_base::hex, locale("")); basic_icvt_functor<double, TChar> cvtf1(cvt1); vector<double> vec_doubles1(10, 0.0); transform( vec_strings.begin(), vec_strings.end(), // from vec_doubles1.begin(), // to cvtf1 ); for (int i = 0; i != vec_doubles.size(); ++i) { assert(vec_doubles[1] == vec_doubles1[i]); } } // test functor functionality of basic_i(o)cvt objects template <typename TChar> void test_functor2() { basic_iocvt<TChar> cvt(ios_base::hex, locale("")); vector<double> vec_doubles(10, 1.2); vector< basic_string<TChar> > vec_strings; transform( vec_doubles.begin(), vec_doubles.end(), // from back_inserter(vec_strings), // to cvt ); basic_icvt_functor<double, TChar> cvtf1(cvt); vector<double> vec_doubles1(10, 0.0); transform( vec_strings.begin(), vec_strings.end(), // from vec_doubles1.begin(), // to cvtf1 ); for (int i = 0; i != vec_doubles.size(); ++i) { assert(vec_doubles[1] == vec_doubles1[i]); } } template <typename TChar> void test_string_to() { test_performance1<TChar>(); test_functor1<TChar>(); test_functor2<TChar>(); } int main(int argc, char* argv[]) { cout << test_ovl() << test_to_string<char>(); wcout << wtest_ovl() << test_to_string<wchar_t>(); test_ovl1(); test_string_to<char>(); wtest_ovl1(); test_string_to<wchar_t>(); return 0; } // scvt.hpp // Copyright Oleg Abrosimov 2006. // Distributed under the Boost Software License, Version 1.0. (See // accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) // // the proposal for type to string and // string to type conversions for C++ #ifndef BOOST_STRING_CONVERSIONS_INCLUDED // 1) type to string: // requirements: // 1) controlling the conversions via facets (locales) // 2) compactness of resulting code // 3) full power of iostreams in simple interface. // All fuctionality accessible with iostreams // (through manipulators) should be accessible. #include <string> #include <locale> #include <ios> #include <boost/operators.hpp> /* conversion (cvt) is modeled after iostreams. The relation is: external data sources <-> user data (in a program) ios: external data sources - char sequence (from some device) cvt: external data sources - some string type (from user input) The hierarchy in cvt is the same as in ios: cvt_base ^ | basic_cvt<> ^ ^ / \ basic_icvt<> basic_ocvt<> ^ ^ \ / basic_iocvt<> Templated classes in this hierarchy are parameterized on character type (to support third-party strings) and on a string type, defaults to std::basic_string<char_type> rationale: to provide native support for any string type */ namespace boost { // common functionality independent of char_type class cvt_base { public : // the state of conversion (like iostate) // erange means result is out_of_range of target type // fail means that string format can not be parsed // it must not be a typedef because we want to // overload on it struct cvtstate : bitwise<cvtstate> { unsigned int value; explicit cvtstate(int val) : value(val) {} cvtstate& operator |= (cvtstate const& s) { value |= s.value; } cvtstate& operator &= (cvtstate const& s) { value &= s.value; } cvtstate& operator ^= (cvtstate const& s) { value ^= s.value; } }; static const cvtstate goodbit; static const cvtstate failbit; static const cvtstate erangebit; cvt_base(); explicit cvt_base(std::locale const&); explicit cvt_base(std::ios_base::fmtflags); cvt_base(std::ios_base::fmtflags, std::locale const&); // exactly as in ios_base std::locale getloc() const; std::locale imbue(const std::locale&); std::ios_base::fmtflags flags() const; std::ios_base::fmtflags flags(std::ios_base::fmtflags); std::streamsize precision() const; std::streamsize precision(std::streamsize); std::streamsize width() const; std::streamsize width(std::streamsize); void setf(std::ios_base::fmtflags mask); std::ios_base::fmtflags setf(std::ios_base::fmtflags mask, std::ios_base::fmtflags unset); void unsetf(std::ios_base::fmtflags mask); // exactly as in basic_ios<> cvt_base& copyfmt(const cvt_base&); // cvtstate related operations bool bad() const; bool fail() const; bool erange() const; bool good() const; void clear(cvtstate s = goodbit); cvtstate exceptions() const; cvtstate exceptions(cvtstate); cvtstate rdstate() const; void setstate(cvtstate); }; const cvt_base::cvtstate cvt_base::goodbit = cvt_base::cvtstate(0); const cvt_base::cvtstate cvt_base::failbit = cvt_base::cvtstate(1); const cvt_base::cvtstate cvt_base::erangebit = cvt_base::cvtstate(2); // common char_type dependent functionality template < typename TChar, typename TStr = std::basic_string<TChar> > class basic_cvt : public cvt_base { typedef basic_cvt<TChar, TStr> this_type; public : typedef TChar char_type; typedef TStr string_type; basic_cvt(); explicit basic_cvt(std::locale const&); explicit basic_cvt(std::ios_base::fmtflags); basic_cvt(std::ios_base::fmtflags, std::locale const&); // exactly as in basic_ios<> char_type fill() const; char_type fill(char_type); char_type widen(char); char narrow(char_type, char = '\0'); // safe bool idiom typedef char_type * this_type::*unspecified_bool_type; //exposition only operator unspecified_bool_type() const; }; // 1) it can be used as a functor in std algorithms // 2) it can be used to improve performance // 3) it can be used to improve code readability, especially when // non-default fmtflags or locale is used template < typename TChar, typename TStr = std::basic_string<TChar> > class basic_ocvt : public virtual basic_cvt<TChar, TStr> { public : typedef TChar char_type; typedef TStr string_type; basic_ocvt(); explicit basic_ocvt(std::locale const&); explicit basic_ocvt(std::ios_base::fmtflags); basic_ocvt(std::ios_base::fmtflags, std::locale const&); // can throw bad_alloc error template <typename T> string_type operator() (T const&); }; typedef basic_ocvt<char> ocvt; typedef basic_ocvt<wchar_t> wocvt; // auxilary functions: to_string/to_wstring // can throw bad_alloc error #define BOOST_PP_DECLARE_TO_STRING_FUNCS(STR_TYPE) \ template <typename T> \ std::STR_TYPE to_##STR_TYPE(T const&); \ template <typename T> \ std::STR_TYPE to_##STR_TYPE(T const&, std::locale const&); \ template <typename T> \ std::STR_TYPE to_##STR_TYPE(T const&, std::ios_base::fmtflags); \ template <typename T> \ std::STR_TYPE to_##STR_TYPE(T const&, std::ios_base::fmtflags, std::locale const&); BOOST_PP_DECLARE_TO_STRING_FUNCS(string) BOOST_PP_DECLARE_TO_STRING_FUNCS(wstring) #undef BOOST_PP_DECLARE_TO_STRING_FUNCS } // namespace boost // 2) string to type: // requirements: // 0) the input string should be valid, in a sense that the following code // should works as expected: // std::istringstream is(input_string); // Type t; // is >> t; // // 1) built-in integral types (int, short, char, long and unsigned versions) // 2) built-in floating point types (float, double) // 3) UDT // // (1) and (2) are processed with stoXXX funcs // (3) is processed with std::stringstream // // Throws: invalid_argument if no conversion could be performed. // Throws: range_error if the converted value is outside the range // of representable values for the return type. // // 1) error handling and reporting. (what kind of error occured?) // * optionally report failing without exceptions raising // 2) check if the output was actually generated from the complete input // example: lexical_cast<double>("1,2") // * the issue here: is it required to the string given // be a full representation of only one entity? // It is different from iostreams-based approach, // but seems reasonable enough. // 3) controlling the conversions via facets (locales) // 4) performance should be guaranted for built-in types at least. // It can be done in terms of strtod-like functions // 5) compactness of resulting code // 6) full power of iostreams in simple interface. // All fuctionality accessible with iostreams // (through manipulators) should be accessible. namespace boost { // 1) it can be used as a functor in std algorithms // through basic_icvt_functor adapter // 2) it can be used to improve performance when many input is done // 3) it can be used to improve code readability, especially when // non-default std::ios_base::fmtflags or locale is used template < typename TChar, typename TStr = std::basic_string<TChar> > class basic_icvt : public virtual basic_cvt<TChar, TStr> { public : typedef TChar char_type; typedef TStr string_type; basic_icvt(); explicit basic_icvt(std::locale const&); // hex, oct, dec seems to be usefull here // skipws is set by default explicit basic_icvt(std::ios_base::fmtflags); basic_icvt(std::ios_base::fmtflags, std::locale const&); // constructors with exception info provided basic_icvt(cvtstate except); basic_icvt(cvtstate except, std::locale const&); basic_icvt(std::ios_base::fmtflags, cvtstate except); basic_icvt(std::ios_base::fmtflags, cvtstate except, std::locale const&); // Throws: invalid_argument if no conversion could be performed // and failbit is set // Throws: range_error if the converted value is outside the range // of representable values for the return type and erangebit is set. template <typename Target> void operator() (string_type const&, Target&); template <typename Target> void operator() (const char_type *const, Target&); // we don't care about possible errors here. // just return _default if unsuccessful. // Note: exceptions are not thrown, // but cvtstate is set to the reason why conversion was failed template <typename Target> void operator() (string_type const&, Target&, Target const& _default); template <typename Target> void operator() (const char_type *const, Target&, Target const& _default); }; typedef basic_icvt<char> icvt; typedef basic_icvt<wchar_t> wicvt; // it provides interface for standart algorithms // basic_icvt<char> cvt; // basic_icvt_functor<int, char> cvtf(cvt); // int i = cvtf("11"); // assert (i == 11); // // it can be used with basic_iocvt<> as well // // alternative whould be to add a Target parameter to // basic_icvt<>, but it means that user should instantiate // new basic_icvt<> for each Target type in her code. // it whould be inefficient. template < typename Target, typename TChar, typename TStr = std::basic_string<TChar> > class basic_icvt_functor { public : typedef TChar char_type; typedef TStr string_type; typedef basic_icvt<TChar, TStr> basic_icvt_type; typedef Target result_type; basic_icvt_functor(basic_icvt_type& _icvt) : m_picvt(&_icvt) {} result_type operator() (string_type const& src) { result_type t; (*m_picvt)(src, t); return t; } result_type operator() (const char_type *const src) { result_type t; (*m_picvt)(src, t); return t; } result_type operator() (string_type const& src, result_type const& _default) { result_type t; (*m_picvt)(src, t, _default); return t; } result_type operator() (const char_type *const src, result_type const& _default) { result_type t; (*m_picvt)(src, t, _default); return t; } private : basic_icvt_type* m_picvt; }; // template typedef template <typename Target> class icvt_functor : public basic_icvt_functor<Target, char, std::string> { public : typedef char char_type; typedef std::string string_type; typedef basic_icvt<char, std::string> basic_icvt_type; typedef Target result_type; icvt_functor(basic_icvt_type& _icvt) : basic_icvt_functor<Target, char, std::string>(_icvt) {} }; // template typedef template <typename Target> class wicvt_functor : public basic_icvt_functor<Target, wchar_t, std::wstring> { public : typedef wchar_t char_type; typedef std::wstring string_type; typedef basic_icvt<wchar_t, std::wstring> basic_icvt_type; typedef Target result_type; wicvt_functor(basic_icvt_type& _icvt) : basic_icvt_functor<Target, wchar_t, std::wstring>(_icvt) {} }; // versions with "T const&" argument don't generate exceptions // or report error conditions, they returns the value specified with // the parameter in question instead // // if no default value and no "cvt_base::cvtstate&" are provided // it can generate invalid_argument or range_error exceptions // // versions with "cvt_base::cvtstate&" argument // don't generate exceptions, but write reason for error // in parameter in question instead. // The default constructed value is returned in this case. // // mixed case returns the default parameter and writes reason for error // in "cvt_base::cvtstate&" parameter // // "std::ios_base::fmtflags" parameter can be used to specify // base for integral types: oct|dec|hex #define BOOST_PP_DECLARE_STRING_TO_CONVERTOR_FUNCS(STR_TYPE) \ template <typename T> \ T string_to(STR_TYPE); \ template <typename T> \ T string_to(STR_TYPE, T const&); \ template <typename T> \ T string_to(STR_TYPE, cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, T const&, cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, std::locale const&); \ template <typename T> \ T string_to(STR_TYPE, T const&, std::locale const&); \ template <typename T> \ T string_to(STR_TYPE, std::locale const&, \ cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, T const&, std::locale const&, \ cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, std::ios_base::fmtflags); \ template <typename T> \ T string_to(STR_TYPE, T const&, \ std::ios_base::fmtflags); \ template <typename T> \ T string_to(STR_TYPE, std::ios_base::fmtflags, \ cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, T const&, std::ios_base::fmtflags, \ cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, std::ios_base::fmtflags, \ std::locale const&); \ template <typename T> \ T string_to(STR_TYPE, T const, std::ios_base::fmtflags, \ std::locale const&); \ template <typename T> \ T string_to(STR_TYPE, std::ios_base::fmtflags, \ std::locale const&, cvt_base::cvtstate&); \ template <typename T> \ T string_to(STR_TYPE, T const&, std::ios_base::fmtflags, \ std::locale const&, cvt_base::cvtstate&); BOOST_PP_DECLARE_STRING_TO_CONVERTOR_FUNCS(std::string const&) BOOST_PP_DECLARE_STRING_TO_CONVERTOR_FUNCS(std::wstring const&) BOOST_PP_DECLARE_STRING_TO_CONVERTOR_FUNCS(const char *const) BOOST_PP_DECLARE_STRING_TO_CONVERTOR_FUNCS(const wchar_t *const) #undef BOOST_PP_DECLARE_STRING_TO_CONVERTOR_FUNCS // 1) it can be used as a functor in std algorithms // through basic_icvt_functor adapter // 2) it can be used to improve performance when many input is done // 3) it can be used to improve code readability, especially when // non-default std::ios_base::fmtflags or locale is used template < typename TChar, typename TStr = std::basic_string<TChar> > class basic_iocvt : public basic_icvt<TChar, TStr>, public basic_ocvt<TChar, TStr> { public : typedef TChar char_type; typedef TStr string_type; basic_iocvt(); explicit basic_iocvt(std::locale const&); // hex, oct, dec seems to be usefull here // skipws is set by default explicit basic_iocvt(std::ios_base::fmtflags); basic_iocvt(std::ios_base::fmtflags, std::locale const&); // constructors with exception info provided basic_iocvt(cvtstate except); basic_iocvt(cvtstate except, std::locale const&); basic_iocvt(std::ios_base::fmtflags, cvtstate except); basic_iocvt(std::ios_base::fmtflags, cvtstate except, std::locale const&); // make it visible in an equal degree using basic_icvt<TChar, TStr>::operator (); using basic_ocvt<TChar, TStr>::operator (); }; typedef basic_iocvt<char, std::string> iocvt; typedef basic_iocvt<wchar_t, std::wstring> wiocvt; } // namespace boost #define BOOST_STRING_CONVERSIONS_INCLUDED #endif //BOOST_STRING_CONVERSIONS_INCLUDED