Last active
August 29, 2015 14:00
-
-
Save kainjow/11278475 to your computer and use it in GitHub Desktop.
Emulates QString's arg() behavior in C++11
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Public domain. | |
#include <iostream> | |
#include <string> | |
namespace { | |
template <typename T> | |
class fmt_base { | |
public: | |
fmt_base(const T& str) : str_(str) {} | |
fmt_base& arg(const T& a) { | |
typename T::size_type lowest_pos = T::npos; | |
typename T::value_type lowest_value = 10; | |
for (typename T::size_type i = 0, l = str_.size() - 1; i < l; ++i) { | |
if (str_[i] == '%') { | |
typename T::value_type val = str_[i + 1]; | |
if ((val >= '1' && val <= '9') && (val - '0') < lowest_value) { | |
lowest_value = val - '0'; | |
lowest_pos = i; | |
} | |
} | |
} | |
if (lowest_pos != T::npos) { | |
str_.replace(lowest_pos, 2, a); | |
} | |
return *this; | |
} | |
fmt_base& arg(int a) { return arg(std::to_string(a)); } | |
fmt_base& arg(unsigned int a) { return arg(std::to_string(a)); } | |
fmt_base& arg(long long a) { return arg(std::to_string(a)); } | |
fmt_base& arg(unsigned long long a) { return arg(std::to_string(a)); } | |
fmt_base& arg(double a, int precision = -1) { | |
if (precision == -1) { | |
return arg(std::to_string(a)); | |
} | |
char buf[20]; | |
#if _MSC_VER | |
#define SNPRINTF ::_snprintf_s | |
#else | |
#define SNPRINTF ::snprintf | |
#endif | |
switch (precision) { | |
case 0: SNPRINTF(buf, sizeof(buf), "%.0f", a); break; | |
case 1: SNPRINTF(buf, sizeof(buf), "%.1f", a); break; | |
case 2: SNPRINTF(buf, sizeof(buf), "%.2f", a); break; | |
default: SNPRINTF(buf, sizeof(buf), "%.3f", a); break; | |
} | |
#undef SNPRINTF | |
return arg(buf); | |
} | |
template <typename A> fmt_base& operator()(const A& a) { return arg(a); } | |
template <typename A> fmt_base& operator[](const A& a) { return arg(a); } | |
operator T() const { | |
return str_; | |
} | |
private: | |
T str_; | |
}; | |
typedef fmt_base<std::string> fmt; | |
} | |
int main() | |
{ | |
std::string r; | |
r = fmt("Welcome, %2 and %1! Say %3 to my %4-year old fish.")["John"]("Kelly")["hello"][10]; | |
std::cout << r << std::endl; | |
r = fmt("Numbers: %3, %1, %2").arg(1024ULL * 1024ULL * 1024ULL * 1024ULL * 12ULL).arg(42.321, 2).arg(-9000); | |
std::cout << r << std::endl; | |
#if _MSC_VER | |
system("pause"); | |
#endif | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
This is an experiment that emulates QString's (from Qt) arg() method using only standard C++11. Seems to work reasonably well, although I've only tested with Visual Studio 2013.
Could be made much more efficient by caching the offsets of the percentage values in the constructor instead of each call to arg().