/* $Id$
This file is part of libmspstrings
-Copyright © 2006-2007 Mikko Rasa
+Copyright © 2006-2008 Mikko Rasa
Distributed under the LGPL
*/
Since type information for conversions is acquired through templates, the
meaning of the conversion specifier character is reduced to only specifying
-what the conversion should look like. In particular, the d, i, u, c and s
-conversions are no-ops.
+what the conversion should look like. Of special note is the s conversion,
+which will result in a default conversion for any data type. Size modifiers
+are not supported and there is no difference between signed and unsigned
+conversions.
+
+Some new conversions are supported:
+
+ b/B Binary integer conversion
+ P Uppercase pointer conversion (like %#X)
*/
class Fmt
{
public:
- Fmt() { reset(); }
- Fmt(const char *f) { reset(); parse(f); }
- Fmt(const std::string &f) { reset(); parse(f.c_str()); }
- Fmt &width(unsigned w) { wd=w; return *this; }
- Fmt &precision(unsigned p) { prec=p; return *this; }
- Fmt &showpos(bool s=true) { spos=s; return *this; }
- Fmt &fill(wchar_t f) { fillc=f; return *this; }
- Fmt &fixed() { fmode=FIXED; return *this; }
- Fmt &scientific() { fmode=SCI; return *this; }
- Fmt &showpoint(bool s=true) { spoint=s; return *this; }
- Fmt &showbase(bool s=true) { sbase=s; return *this; }
- Fmt &left() { align=LEFT; return *this; }
- Fmt &right() { align=RIGHT; return *this; }
- Fmt &dec() { base=DEC; return *this; }
- Fmt &hex() { base=HEX; return *this; }
- Fmt &oct() { base=OCT; return *this; }
- Fmt &uppercase(bool u=true) { ucase=u; return *this; }
- Fmt &reset();
- void apply(std::ostream &) const;
-private:
+ enum Type
+ {
+ NUM,
+ CHAR,
+ STR
+ };
+
enum Base
{
- DEC,
- HEX,
- OCT
+ AUTOBASE = 0,
+ DEC = 10,
+ HEX = 16,
+ OCT = 8,
+ BIN = 2
};
enum FloatMode
{
FIXED,
- EXP,
+ AUTOFLT,
SCI
};
RIGHT
};
+private:
unsigned wd;
unsigned prec;
bool spos;
bool spoint;
Align align;
bool ucase;
+ Type type;
+
+public:
+ Fmt() { reset(); }
+ Fmt(const char *f) { reset(); parse(f); }
+ Fmt(const std::string &f) { reset(); parse(f.c_str()); }
+
+ Fmt &width(unsigned w) { wd=w; return *this; }
+ Fmt &precision(unsigned p) { prec=p; return *this; }
+ Fmt &showpos(bool s=true) { spos=s; return *this; }
+ Fmt &fill(wchar_t f) { fillc=f; return *this; }
+ Fmt &fixed() { fmode=FIXED; return *this; }
+ Fmt &scientific() { fmode=SCI; return *this; }
+ Fmt &showpoint(bool s=true) { spoint=s; return *this; }
+ Fmt &showbase(bool s=true) { sbase=s; return *this; }
+ Fmt &left() { align=LEFT; return *this; }
+ Fmt &right() { align=RIGHT; return *this; }
+ Fmt &dec() { base=DEC; return *this; }
+ Fmt &hex() { base=HEX; return *this; }
+ Fmt &oct() { base=OCT; return *this; }
+ Fmt &bin() { base=BIN; return *this; }
+ Fmt &uppercase(bool u=true) { ucase=u; return *this; }
+ Fmt &numeric() { type=NUM; return *this; }
+ Fmt &character() { type=CHAR; return *this; }
+ Fmt &string() { type=STR; return *this; }
+ Fmt &reset();
+ unsigned get_width() const { return wd; }
+ unsigned get_precision() const { return prec; }
+ bool get_showpos() const { return spos; }
+ wchar_t get_fill() const { return fillc; }
+ Base get_base() const { return base; }
+ bool get_showbase() const { return sbase; }
+ FloatMode get_floatmode() const { return fmode; }
+ bool get_showpoint() const { return spoint; }
+ Align get_align() const { return align; }
+ bool get_uppercase() const { return ucase; }
+ Type get_type() const { return type; }
+
+ void apply(std::ostream &) const;
+private:
void parse(const char *);
};
--- /dev/null
+/* $Id$
+
+This file is part of libmspstrings
+Copyright © 2006-2008 Mikko Rasa
+Distributed under the LGPL
+*/
+
+#include <cmath>
+#include <limits>
+#include "lexicalcast.h"
+
+using namespace std;
+
+namespace {
+
+using namespace Msp;
+
+template<typename T>
+struct IsSigned
+{ enum { result=!(static_cast<T>(-1)>0) }; };
+
+template<typename T, bool f=(sizeof(T)>sizeof(unsigned long))>
+struct Temporary
+{ typedef unsigned long Type; };
+
+template<typename T>
+struct Temporary<T, true>
+{
+#ifdef WIN32
+ typedef __int64 Type;
+#else
+ typedef unsigned long long Type;
+#endif
+};
+
+/* Helper to avoid warnings about an unsigned type never being < 0 */
+template<typename T, bool f=IsSigned<T>::result>
+struct IsNegative
+{ static bool eval(T v) { return v<0; } };
+
+template<typename T>
+struct IsNegative<T, false>
+{ static bool eval(T) { return false; } };
+
+/* Helper to avoid errors about ambiguous function calls since there are no
+overloads of abs for unsigned types */
+template<typename T, bool f=IsSigned<T>::result>
+struct Absolute
+{ static T eval(T v) { return v<0 ? -v : v; } };
+
+template<typename T>
+struct Absolute<T, false>
+{ static T eval(T v) { return v; } };
+
+
+/*** Integer conversions ***/
+
+const char udigits[]="0123456789ABCDEF";
+const char ldigits[]="0123456789abcdef";
+
+template<typename T>
+char *int_to_str(T v, const Fmt &f, char *end)
+{
+ if(f.get_type()==Fmt::CHAR)
+ {
+ *--end=v;
+ return end;
+ }
+
+ char *ptr=end;
+
+ // Find out the base to use
+ unsigned base=f.get_base();
+ if(!base)
+ base=10;
+
+ // Format the number, starting from the least significant digit
+ const char *digits=(f.get_uppercase() ? udigits : ldigits);
+ if(v)
+ {
+ typename Temporary<T>::Type w=Absolute<T>::eval(v);
+ while(w)
+ {
+ *--ptr=digits[w%base];
+ w/=base;
+ }
+ }
+ else
+ *--ptr=digits[0];
+
+ char sign=(IsNegative<T>::eval(v) ? '-' : f.get_showpos() ? '+' : 0);
+ if(f.get_fill()=='0')
+ {
+ /* Zero-fill, taking base/sign size into account. The expression is a
+ bit ugly, but saves having to write code for creating the prefix both
+ ways. */
+ unsigned pfxsize=((f.get_showbase() && base!=10) ? base==8 ? 1 : 2 : 0) + (sign!=0);
+ for(unsigned i=(end-ptr)+pfxsize; i<f.get_width(); ++i)
+ *--ptr='0';
+ }
+
+ if(f.get_showbase() && v!=0)
+ {
+ // Add base indicator
+ if(base==2)
+ *--ptr=(f.get_uppercase() ? 'B' : 'b');
+ else if(base==16)
+ *--ptr=(f.get_uppercase() ? 'X' : 'x');
+ if(base!=10)
+ *--ptr='0';
+ }
+
+ if(sign)
+ *--ptr=sign;
+
+ return ptr;
+}
+
+template<typename T>
+string int_to_str(T v, const Fmt &f)
+{
+ unsigned size=max(f.get_width(), max(f.get_precision(), sizeof(T)*8+3));
+ char *buf=new char[size];
+ string result(int_to_str(v, f, buf+size), buf+size);
+ delete[] buf;
+ return result;
+}
+
+template<typename T>
+T str_to_int(const std::string &s, const Fmt &f)
+{
+ if(s.empty())
+ throw LexicalError("Empty input in integer conversion");
+
+ std::string::const_iterator i=s.begin();
+
+ // See if the input starts with a sign
+ bool neg=false;
+ if(*i=='-')
+ {
+ if(!IsSigned<T>::result)
+ throw LexicalError("Negative sign in unsigned integer conversion");
+ neg=true;
+ ++i;
+ }
+ else if(*i=='+')
+ ++i;
+
+ // Must have some digits to convert
+ if(i==s.end())
+ throw LexicalError("Missing digits in integer conversion");
+
+ T base=f.get_base();
+ if(!base && i!=s.end())
+ {
+ // Automatic base detection requested, figure it out
+ if(*i=='0' && ++i!=s.end())
+ {
+ if(*i=='x' || *i=='X')
+ {
+ base=16;
+ ++i;
+ }
+ else if(*i=='b' || *i=='B')
+ {
+ base=2;
+ ++i;
+ }
+ else
+ base=8;
+ }
+ else
+ base=10;
+ }
+
+ // Parse the digits
+ T result=0;
+ for(; i!=s.end(); ++i)
+ {
+ T digit=base;
+ if(*i>='0' && *i<='9')
+ digit=*i-'0';
+ else if(*i>='A' && *i<='F')
+ digit=*i-'A'+10;
+ else if(*i>='a' && *i<='f')
+ digit=*i-'a'+10;
+ if(digit>=base)
+ throw LexicalError("Invalid digit in integer conversion");
+ T next=result*base+digit;
+ if(next/base!=result)
+ throw LexicalError("Overflow in integer conversion");
+ result=next;
+ }
+
+ if(neg)
+ result=-result;
+
+ return result;
+}
+
+
+/*** Boolean conversions ***/
+
+string bool_to_str(bool b, const Fmt &f)
+{
+ if(f.get_type()==Fmt::STR)
+ return b ? "true" : "false";
+ else
+ return b ? "1" : "0";
+}
+
+bool str_to_bool(const string &s)
+{
+ if(s=="1" || s=="true" || s=="yes" || s=="on")
+ return true;
+ else if(s=="0" || s=="false" || s=="no" || s=="off")
+ return true;
+ throw LexicalError("Invalid input in boolean conversion");
+}
+
+
+/*** Floating-point conversions ***/
+
+template<typename T>
+string flt_to_str(T v, const Fmt &f)
+{
+ if(f.get_type()==Fmt::CHAR)
+ throw LexicalError("Character format in floating-point conversion");
+
+ Fmt::FloatMode mode=f.get_floatmode();
+ long double w=abs(v);
+ char sign=(v<0 ? '-' : f.get_showpos() ? '+' : 0);
+
+ // Handle infinity and not-a-number as special cases
+ if(!(w+w>w) && w!=0)
+ {
+ string result;
+ if(sign)
+ result+=sign;
+ if(!(w>=0))
+ result+=(f.get_uppercase() ? "NAN" : "nan");
+ else
+ result+=(f.get_uppercase() ? "INF" : "inf");
+ if(result.size()<f.get_width())
+ result=string(f.get_width()-result.size(), ' ')+result;
+ return result;
+ }
+
+ /* Find out the base-10 exponent. Building up the multiplier / divisor
+ first helps with accuracy in some cases. */
+ int exp=0;
+ if(w>=10)
+ {
+ long double div=1;
+ while(div*10<w)
+ {
+ ++exp;
+ div*=10;
+ }
+ w/=div;
+ }
+ else if(mode!=Fmt::FIXED && w<1 && w!=0)
+ {
+ long double mul=1;
+ while(w*mul<1)
+ {
+ --exp;
+ mul*=10;
+ }
+ w*=mul;
+ }
+
+ // Decide how to format the number
+ unsigned digits;
+ unsigned point=1;
+ bool showexp=false;
+ if(mode==Fmt::FIXED)
+ {
+ point=exp+1;
+ digits=point+f.get_precision();
+ }
+ else if(mode==Fmt::SCI)
+ {
+ digits=f.get_precision()+1;
+ showexp=true;
+ }
+ else
+ {
+ digits=max(f.get_precision(), 1U);
+ if(exp<-4 || exp>=static_cast<int>(digits))
+ {
+ point=1;
+ showexp=true;
+ }
+ else
+ {
+ point=max(exp, 0)+1;
+ if(exp<0)
+ digits+=-exp;
+ }
+ }
+
+ // Apply rounding
+ w+=5.0l/pow(10.0l, digits);
+ if(w>10)
+ {
+ // Rounding bumped us to the next exponent, deal with it
+ w/=10;
+ if(mode==Fmt::AUTOFLT && exp+1==static_cast<int>(digits))
+ {
+ point=1;
+ showexp=true;
+ }
+ if(!showexp)
+ {
+ ++digits;
+ ++point;
+ }
+ else
+ ++exp;
+ }
+
+ // Create a buffer and start from the end
+ unsigned size=max(f.get_width(), digits+8);
+ char *buf=new char[size];
+ char *end=buf+size;
+ char *ptr=end;
+
+ // Format exponent
+ if(showexp)
+ {
+ ptr=int_to_str(exp, Fmt().showpos().fill('0').width(3), ptr);
+ *--ptr=(f.get_uppercase() ? 'E' : 'e');
+ }
+
+ // Format mantissa left-to-right
+ char *eptr=ptr;
+ ptr-=digits+(point<digits || f.get_showpoint());
+ char *mptr=ptr;
+ for(unsigned i=0; i<digits; ++i)
+ {
+ if(i==point)
+ *mptr++='.';
+ if(showexp || static_cast<int>(i)>=-exp)
+ {
+ int digit=static_cast<int>(w);
+ *mptr++='0'+digit;
+ w=(w-digit)*10;
+ }
+ else
+ *mptr++='0';
+ }
+
+ if(f.get_showpoint())
+ {
+ // Radix point requested but not displayed yet, add it
+ if(digits<=point)
+ *mptr++='.';
+ }
+ else if(mode==Fmt::AUTOFLT && digits>point)
+ {
+ // Remove trailing zeroes from fraction and a lone radix point
+ while(mptr[-1]=='0')
+ --mptr;
+ if(mptr[-1]=='.')
+ --mptr;
+ if(mptr!=eptr)
+ {
+ while(mptr!=ptr)
+ *--eptr=*--mptr;
+ ptr=eptr;
+ }
+ }
+
+ // Add filling and sign
+ if(f.get_fill()=='0')
+ {
+ unsigned pfxlen=(sign!=0);
+ while(end-ptr+pfxlen<f.get_width())
+ *--ptr='0';
+ }
+ if(sign)
+ *--ptr=sign;
+
+ string result(ptr, end);
+ delete[] buf;
+ return result;
+}
+
+template<typename T>
+T str_to_flt(const string &s, const Fmt &)
+{
+ if(s.empty())
+ throw LexicalError("Empty input in floating-point conversion");
+
+ std::string::const_iterator i=s.begin();
+
+ // See if the input starts with a sign
+ bool neg=false;
+ if(*i=='-')
+ {
+ neg=true;
+ ++i;
+ }
+ else if(*i=='+')
+ ++i;
+
+ // Must have some digits to convert
+ if(i==s.end())
+ throw LexicalError("Missing digits in floating-point conversion");
+
+ long double v=0;
+ int exp=0;
+
+ // Parse mantissa
+ bool point_seen=false;
+ for(; i!=s.end(); ++i)
+ {
+ if(*i=='.')
+ {
+ if(point_seen)
+ throw LexicalError("Extra point in floating-point conversion");
+ point_seen=true;
+ }
+ else if(*i>='0' && *i<='9')
+ {
+ v=v*10+(*i-'0');
+ if(point_seen)
+ --exp;
+ }
+ else if(*i=='e' || *i=='E')
+ {
+ // We have an exponent
+ ++i;
+
+ exp+=str_to_int<int>(string(i, s.end()), Fmt());
+ // str_to_int has eaten the rest of the input or thrown
+ break;
+ }
+ else
+ throw LexicalError("Invalid digit in floating-point conversion");
+ }
+
+ // Scale and negate the result as needed
+ while(exp>0)
+ {
+ v*=10;
+ --exp;
+ }
+ while(exp<0)
+ {
+ v/=10;
+ ++exp;
+ }
+
+ if(neg)
+ v=-v;
+
+ return v;
+}
+
+
+/*** String conversions ***/
+
+string str_to_str(const string &s, const Fmt &f)
+{
+ if(f.get_type()==Fmt::NUM)
+ throw LexicalError("Numeric format in string conversion");
+ return s;
+}
+
+}
+
+namespace Msp {
+
+void LexicalConverter::result(const string &s)
+{
+ if(s.size()<fmt.get_width())
+ {
+ if(fmt.get_align()==Fmt::RIGHT)
+ buf=string(fmt.get_width()-s.size(), fmt.get_fill())+s;
+ else
+ buf=s+string(fmt.get_width()-s.size(), fmt.get_fill());
+ }
+ else
+ buf=s;
+}
+
+
+/*** operator<< ***/
+
+void operator<<(LexicalConverter &c, char v)
+{
+ Fmt::Type type=c.get_fmt().get_type();
+ if(type==Fmt::NUM)
+ c.result(int_to_str(v, c.get_fmt()));
+ else
+ c.result(string(1, v));
+}
+
+void operator<<(LexicalConverter &c, signed char v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, short v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, int v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, long v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, unsigned char v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, unsigned short v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, unsigned v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, unsigned long v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+#ifdef __GNUC__
+void operator<<(LexicalConverter &c, long long v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, unsigned long long v)
+{ c.result(int_to_str(v, c.get_fmt())); }
+#endif
+
+void operator<<(LexicalConverter &c, bool v)
+{ c.result(bool_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, float v)
+{ c.result(flt_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, double v)
+{ c.result(flt_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, long double v)
+{ c.result(flt_to_str(v, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, const string &s)
+{ c.result(str_to_str(s, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, const char *s)
+{ c.result(str_to_str(s, c.get_fmt())); }
+
+void operator<<(LexicalConverter &c, const void *p)
+{ c.result(int_to_str(reinterpret_cast<unsigned long>(p), c.get_fmt())); }
+
+
+/*** operator>> ***/
+
+void operator>>(const LexicalConverter &c, char &v)
+{
+ if(c.get_fmt().get_type()==Fmt::NUM)
+ v=str_to_int<char>(c.get(), c.get_fmt());
+ else
+ {
+ const std::string &s=c.get();
+ if(s.empty())
+ throw LexicalError("Empty input in character conversion");
+ if(s.size()>1)
+ throw LexicalError("Extra input in character conversion");
+ v=s[0];
+ }
+}
+
+void operator>>(const LexicalConverter &c, signed char &v)
+{ v=str_to_int<signed char>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, short &v)
+{ v=str_to_int<short>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, int &v)
+{ v=str_to_int<int>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, long &v)
+{ v=str_to_int<long>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, unsigned char &v)
+{ v=str_to_int<unsigned char>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, unsigned short &v)
+{ v=str_to_int<unsigned short>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, unsigned int &v)
+{ v=str_to_int<unsigned int>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, unsigned long &v)
+{ v=str_to_int<unsigned long>(c.get(), c.get_fmt()); }
+
+#ifdef __GNUC__
+void operator>>(const LexicalConverter &c, long long &v)
+{ v=str_to_int<long long>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, unsigned long long &v)
+{ v=str_to_int<unsigned long long>(c.get(), c.get_fmt()); }
+#endif
+
+void operator>>(const LexicalConverter &c, bool &v)
+{ v=str_to_bool(c.get()); }
+
+void operator>>(const LexicalConverter &c, float &v)
+{ v=str_to_flt<float>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, double &v)
+{ v=str_to_flt<double>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, long double &v)
+{ v=str_to_flt<long double>(c.get(), c.get_fmt()); }
+
+void operator>>(const LexicalConverter &c, string &s)
+{ s=str_to_str(c.get(), c.get_fmt()); }
+
+} // namespace Msp
/* $Id$
This file is part of libmspstrings
-Copyright © 2006-2007 Mikko Rasa
+Copyright © 2006-2008 Mikko Rasa
Distributed under the LGPL
*/
namespace Msp {
+/**
+Thrown for errors in lexical conversions
+*/
class LexicalError: public Exception
{
public:
LexicalError(const std::string &w_): Exception(w_) { }
};
-template<typename T>
-T lexical_cast(const std::string &s)
+/**
+Helper class for lexical_cast to facilitate operator overloading.
+*/
+class LexicalConverter
{
- std::istringstream ss(s);
- ss.setf(std::ios_base::fmtflags(0), std::ios_base::skipws);
+private:
+ Fmt fmt;
+ std::string buf;
+
+public:
+ LexicalConverter(const Fmt &f): fmt(f) { }
+ LexicalConverter(const std::string &s, const Fmt &f): fmt(f), buf(s) { }
+
+ const Fmt &get_fmt() const { return fmt; }
+ const std::string &get() const { return buf; }
+ void result(const std::string &);
+};
+
+void operator<<(LexicalConverter &, char);
+void operator<<(LexicalConverter &, signed char);
+void operator<<(LexicalConverter &, short);
+void operator<<(LexicalConverter &, int);
+void operator<<(LexicalConverter &, long);
+void operator<<(LexicalConverter &, unsigned char);
+void operator<<(LexicalConverter &, unsigned short);
+void operator<<(LexicalConverter &, unsigned);
+void operator<<(LexicalConverter &, unsigned long);
+#ifdef __GNUC__
+void operator<<(LexicalConverter &, long long);
+void operator<<(LexicalConverter &, unsigned long long);
+#endif
+void operator<<(LexicalConverter &, bool);
+void operator<<(LexicalConverter &, float);
+void operator<<(LexicalConverter &, double);
+void operator<<(LexicalConverter &, long double);
+void operator<<(LexicalConverter &, const std::string &);
+void operator<<(LexicalConverter &, const char *);
+void operator<<(LexicalConverter &, const void *);
+
+void operator>>(const LexicalConverter &, char &);
+void operator>>(const LexicalConverter &, signed char &);
+void operator>>(const LexicalConverter &, short &);
+void operator>>(const LexicalConverter &, int &);
+void operator>>(const LexicalConverter &, long &);
+void operator>>(const LexicalConverter &, unsigned char &);
+void operator>>(const LexicalConverter &, unsigned short &);
+void operator>>(const LexicalConverter &, unsigned int &);
+void operator>>(const LexicalConverter &, unsigned long &);
+#ifdef __GNUC__
+void operator>>(const LexicalConverter &, long long &);
+void operator>>(const LexicalConverter &, unsigned long long &);
+#endif
+void operator>>(const LexicalConverter &, bool &);
+void operator>>(const LexicalConverter &, float &);
+void operator>>(const LexicalConverter &, double &);
+void operator>>(const LexicalConverter &, long double &);
+void operator>>(const LexicalConverter &, std::string &);
- T tmp;
- ss>>tmp;
+// Generic operators using stringstream
+template<typename T>
+void operator<<(LexicalConverter &c, const T &v)
+{
+ std::ostringstream ss;
+ ss<<c.get_fmt()<<v;
+ c.result(ss.str());
+}
+
+template<typename T>
+void operator>>(const LexicalConverter &c, T &v)
+{
+ std::istringstream ss(c.get());
+ ss.setf(std::ios_base::fmtflags(0), std::ios_base::skipws);
+ ss>>v;
if(ss.fail() || !ss.eof())
throw LexicalError("Conversion failure");
-
- return tmp;
}
-template<>
-inline std::string lexical_cast<std::string>(const std::string &s)
+// The main interface to the lexical conversion machinery
+
+template<typename T>
+inline T lexical_cast(const std::string &s, const Fmt &f=Fmt())
{
- return s;
+ LexicalConverter conv(s, f);
+ T result;
+ conv>>result;
+ return result;
}
template<typename T>
-std::string lexical_cast(const T &v, const Fmt &f=Fmt())
+inline std::string lexical_cast(const T &v, const Fmt &f=Fmt())
{
- std::ostringstream ss;
- ss<<f<<v;
- return ss.str();
+ LexicalConverter conv(f);
+ conv<<v;
+ return conv.get();
}
} // namespace Msp