Created
December 17, 2017 10:38
-
-
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
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
#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