Last active
November 7, 2023 23:06
-
-
Save Zitrax/a2e0040d301bf4b8ef8101c0b1e3f1d5 to your computer and use it in GitHub Desktop.
stringformat with constexpr if
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> | |
/** | |
* Convert all std::strings to const char* using constexpr if (C++17) | |
*/ | |
template<typename T> | |
auto convert(T&& t) { | |
if constexpr (std::is_same<std::remove_cv_t<std::remove_reference_t<T>>, std::string>::value) { | |
return std::forward<T>(t).c_str(); | |
} | |
else { | |
return std::forward<T>(t); | |
} | |
} | |
/** | |
* printf like formatting for C++ with std::string | |
* Original source: https://stackoverflow.com/a/26221725/11722 | |
*/ | |
template<typename ... Args> | |
std::string stringFormatInternal(const std::string& format, Args&& ... args) | |
{ | |
const auto size = snprintf(nullptr, 0, format.c_str(), std::forward<Args>(args) ...) + 1; | |
if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); } | |
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 = "a"; | |
const std::string cs = "b"; | |
const char* cc = "c"; | |
int i = 1; | |
const int i2 = 2; | |
using namespace std::literals; | |
std::cout << stringFormat("%s %s %s %s %s %d %d %d \n", s, cs, cc, "d", "e"s, i, i2, 3); | |
return 0; | |
} |
After not thinking about this for the rest of the day, I came up with this:
It seems to work for me. The only question I have is does it introduce a memory leak with the std::string s? I'm thinking not since it is a local variable.
Also, if I'm bugging you with these comments, let me know, and I'll go away. :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Yeah, and it is probably not possible to fix it safely in the convert function without introducing a memory leak.
I suggest you static_cast your string_view to string when passing them into stringFormat.
Edit: I tried for a couple of hours to make it work with my alternate implementation over here: https://github.com/Dyrcona/libunistdcpp/blob/devel/include/unistd/asprintf.h. The only thing that worked was to use the unsafe (in this context) string_view::data() function.
Maybe someone better at C++ than I can get it to work without a static variable or a memory leak, but most of the things I tried produced gibberish.
I was about to say that the solution is not simple, but maybe it is so simple that it evades me. I did try a few "obvious" things and they didn't work.
The static_cast that I suggested is recommended for other cases where you don't control the API. It's simple, and it works.