#include class ArgsError { }; class TypeError { }; class TPrintfBase { public: virtual void output(char) = 0; }; const char * TPrintfOutput(TPrintfBase * p, const char * fmt, const int & val) throw (ArgsError) { // d for decimal, o for octal, x for hex, X for cap hex char c; int s = 0; bool pad = false; enum { UNK, DEC, OCT, LCH, UCH } printType = UNK; while (printType == UNK && ((c = *fmt++))) { switch (c) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': if (c == '0' && s == 0) pad = true; s = s * 10 + c - '0'; break; case 'd': printType = DEC; break; case 'o': printType = OCT; break; case 'x': printType = LCH; break; case 'X': printType = UCH; break; default: throw ArgsError(); } } if (printType == UNK) throw ArgsError(); // fuck it, somebody else can write the radix conversion char buf[64]; switch (printType) { case DEC: snprintf(buf, 63, pad ? "%0*i" : "%*i", s, val); break; case OCT: snprintf(buf, 63, pad ? "%0*o" : "%*o", s, val); break; case LCH: snprintf(buf, 63, pad ? "%0*x" : "%*x", s, val); break; case UCH: snprintf(buf, 63, pad ? "%0*X" : "%*X", s, val); break; default: /* go fuck yourself, gcc */ ((void) 0); } char * ptr = buf; while ((c = *ptr++)) p->output(c); return fmt; } // generic, catch-all "I don't know the hell is this" template. template const char * TPrintfOutput(TPrintfBase *, const char *, const T &) throw (TypeError) { throw TypeError(); } class TPrintf : public TPrintfBase { public: // tail case void tprintf(const char * s) throw (ArgsError) { while (*s) { if (*s == '%' && *(++s) != '%') throw ArgsError(); output(*s++); } } template void tprintf(const char * fmt, const T & val, Args... args) { while (*fmt) { if (*fmt == '%' && *(++fmt) != '%') { fmt = TPrintfOutput(this, fmt, val); tprintf(fmt, args...); return; } output(*fmt++); } throw ArgsError(); } }; class MyTPrintf : public TPrintf { void output(char c) { fputc(c, stdout); } }; int main() { MyTPrintf p; p.tprintf("%08x: %02x %02x %02x %02x\n", 123456, 42, 64, 36, 43); }