I've written the following code to produce a formatted string (similar, but not identical to the formatting style that System.String.Format() does in .Net), using a combination of boost and the new variadic templates that C++11 offers. I'm looking for criticism, advice, and suggestions for improvement.
Please note: much of the code for handling type-specific formatting is not done. please do not comment on this, unless you have suggestions for its implementation.
Code:#include <sstream> #include <stdexcept> #include <boost/lexical_cast.hpp> template<typename T> std::string BasicToString(const T& t) { return boost::lexical_cast<std::string>(t); } inline std::string Convert(const std::string& fmt, const int& i) { return BasicToString(i); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const long& l) { return BasicToString(l); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const long long& l) { return BasicToString(l); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const unsigned& u) { return BasicToString(u); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const unsigned long& ul) { return BasicToString(ul); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const unsigned long long& ul) { return BasicToString(ul); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const char& c) { return BasicToString(c); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const unsigned char& uc) { return BasicToString(uc); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const short& sh) { return BasicToString(sh); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const unsigned short& ush) { return BasicToString(ush); // TODO: Add formatting capability } inline std::string Convert(const std::string& fmt, const long double& d) // fmt contains the number of digits of precision after the decimal point or a 'C' for currency { std::stringstream ss; if (fmt.empty()) { return BasicToString(d); } else if (fmt[0] == 'C') // process it as currency { ss << "$"; // TODO: get the actual localized currency symbol ss.precision(2); // TODO: Get the actual localized number of digits to print after the decimal point ss << std::fixed << d; return ss.str(); } else { int len = boost::lexical_cast<int>(fmt); ss.precision(len); ss << std::fixed << d; return ss.str(); } } inline std::string Convert(const std::string& fmt, const double& d) // fmt contains the number of digits of precision after the decimal point { std::stringstream ss; if (fmt.empty()) { return BasicToString(d); } else if (fmt[0] == 'C') // process it as currency { ss << "$"; // TODO: get the actual localized currency symbol ss.precision(2); // TODO: Get the actual localized number of digits to print after the decimal point ss << std::fixed << d; return ss.str(); } else { int len = boost::lexical_cast<int>(fmt); ss.precision(len); ss << std::fixed << d; return ss.str(); } } inline std::string Convert(const std::string& fmt, const float& f) // fmt contains the number of digits of precision after the decimal point { std::stringstream ss; if (fmt.empty()) { return BasicToString(f); } else if (fmt[0] == 'C') // process it as currency { ss << "$"; // TODO: get the actual localized currency symbol ss.precision(2); // TODO: Get the actual localized number of digits to print after the decimal point ss << std::fixed << f; return ss.str(); } else { int len = boost::lexical_cast<int>(fmt); ss.precision(len); ss << std::fixed << f; return ss.str(); } } inline std::string Convert(const std::string& fmt, const std::string& s) // fmt contains the minimum width to display, right aligned, padded with spaces { if (fmt.empty()) return BasicToString(s); size_t len = 0; try { len = boost::lexical_cast<int>(fmt); } catch (boost::bad_lexical_cast& ex) { throw std::invalid_argument("Invalid format string. The format string must contain only digits."); } if (s.length() <= len) { std::stringstream ss; ss.width(len); ss.fill(' '); ss << s; return ss.str(); } else return s; } inline std::string Convert(const std::string& fmt, const char* cp) { std::string s(cp); return Convert(fmt, s); } template<typename T> std::string GetArgByIndex(const std::string& argFmt, int index, T& t) { if (index) throw std::invalid_argument("The argument index was out of range."); else return Convert(argFmt, t); } template<typename T, typename ... Args> std::string GetArgByIndex(const std::string& argFmt, int index, T& t, Args ... args) { if (index) return GetArgByIndex(argFmt, index - 1, args...); else return Convert(argFmt, t); } template<typename ... Args> std::string StrFormat(const std::string& fmt, Args ... args) { std::string outString; for (auto it = fmt.begin(); it != fmt.end(); ++it) { if (*it == '{') { // it's possibly the start of an argument ++it; std::string argNum, argFmt; if (*it == '{') // not an argument, just append the literal '{' character outString += *it; else { // process it as an argument string bool isFmtStr = false; while (*it != '}') { switch (*it) { case ':': // the colon indicates the beginning of the format string for this argument { if (isFmtStr) argFmt += *it; // include the colon in the format string. it may be used at a later date else isFmtStr = true; break; } case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { if (isFmtStr) argFmt += *it; else argNum += *it; break; } default: { if (isFmtStr) argFmt += *it; else throw std::invalid_argument("Argument index must be an integer."); break; } } ++it; } size_t index = 0; if (argNum.empty()) throw std::invalid_argument("Empty argument index."); try { index = boost::lexical_cast<size_t>(argNum); } catch (boost::bad_lexical_cast& ex) { throw std::invalid_argument("Argument index must be an integer."); } outString += GetArgByIndex(argFmt, index, args...); } } else // not an argument, just append the literal character outString += *it; } return outString; } inline std::string StrFormat(const std::string& fmt = "") { return fmt; }



LinkBack URL
About LinkBacks


