Skip to content

Instantly share code, notes, and snippets.

@kainjow
Last active August 29, 2015 14:00
Show Gist options
  • Save kainjow/11278475 to your computer and use it in GitHub Desktop.
Save kainjow/11278475 to your computer and use it in GitHub Desktop.
Emulates QString's arg() behavior in C++11
// 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;
}
@kainjow
Copy link
Author

kainjow commented Apr 25, 2014

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().

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment