Skip to content

Instantly share code, notes, and snippets.

@Zitrax
Created December 17, 2017 10:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save Zitrax/ddfe8ed3324b42bdb46bc1bb2a0feef0 to your computer and use it in GitHub Desktop.
Save Zitrax/ddfe8ed3324b42bdb46bc1bb2a0feef0 to your computer and use it in GitHub Desktop.
string format with auto conversion and avoidance of duplications for the const vs non const case
#include <string>
#include <iostream>
#include <memory>
// Since it's not possible to partially specialize a function
// template we use overloads with a rank to try the overloads
// in a specific order.
//
// Using rank introduces "priority" because implicit conversions are required to
// convert a rank<X> to a rank<Y> when X > Y. dispatch first tries to call dummy
// with rank<1>, giving priority to your constrained overloads. If enable_if
// fails, rank<1> is implicitly converted to rank<0> and enters the "fallback"
// case.
//
// See: https://stackoverflow.com/a/44586045/11722
//
template <unsigned int N>
struct rank : rank<N - 1> { };
template <>
struct rank<0> { };
template<typename T, typename U=T>
U convert2(T&& t, rank<0>) {
std::cout << "A " << t << "\n";
return std::forward<T>(t);
}
template<typename T, typename = typename std::enable_if_t<
std::is_same<T, const std::string&>::value ||
std::is_same<T, std::string&>::value
>>
const char* convert2(T&& s, rank<1>) {
std::cout << "B " << s << "\n";
return s.c_str();
}
// Dispatch function calling rank<1> first.
template <typename T>
auto convert(T&& t) {
return convert2(std::forward<T>(t), rank<1>{});
}
template<typename ... Args>
std::string stringFormatInternal(const std::string& format, Args&& ... args)
{
size_t size = snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args) ...) + 1;
std::unique_ptr<char[]> buf(new char[size]);
snprintf(buf.get(), size, format.c_str(), args ...);
return std::string(buf.get(), buf.get() + size - 1);
}
template<typename ... Args>
std::string stringFormat(std::string fmt, Args&& ... args) {
return stringFormatInternal(fmt, convert(std::forward<Args>(args))...);
}
int main() {
std::string s = "test";
const std::string cs = "ctest";
const char* cc = "uff";
int i = 1;
const int i2 = 2;
std::cout << stringFormat("%s %s %s %s %d %d %d \n", s, cs, "a", cc, i, i2, 3);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment