I wrote this function for string concatenation some time ago.
Jo()
stands for "Join". The name is shortened on purpose, because this function is used very often.
It offers a stream-like functionality: Jo("i = ", i)
= cout << "i = " << i
and returns a const char *
to internal buffer.
const char *
is used instead of std::string
because I interact with C apis a lot and writing .c_str()
each time is tedious.
I know that you can achieve same result by converting arguments to std::string
one by one and concatenating them instead of using this function, but it would require a lot more code.
It's intended to be used in a single thread only, thus there are no mutextes or something similar.
Here is the code:
#include <cstdio>
#include <sstream>
#include <initializer_list>
namespace Internal
{
// In real code those are declared `extern` and initialization is moved from .h into .cpp
std::stringstream ss;
const std::stringstream::fmtflags stdfmt = ss.flags();
}
// Jo() resets stringstream flags before performing concatenation.
// Jo_() does not.
template <typename ...P> const char *Jo_(P &&... p)
{
// Multiple buffers to allow use of multiple Jo()'s in a single expression.
static constexpr int ret_buffers_c = 32;
static std::string ret_buffers[ret_buffers_c];
static int ret_pos = 0;
Internal::ss.clear(); // Clear the error flags.
Internal::ss.str(""); // Clear stringstream contents.
// Push all objects to stringstream.
std::initializer_list<int>{(Internal::ss << p, 0)...};
// Save to buffer and return a pointer.
ret_buffers[ret_pos] = Internal::ss.str();
const char *ret = ret_buffers[ret_pos].c_str();
ret_pos = (ret_pos + 1) % ret_buffers_c;
return ret;
}
template <typename ...P> const char *Jo(P &&... p)
{
Internal::ss.flags(Internal::stdfmt);
return Jo_((P &&) p...);
}
// Example usage:
int main()
{
for (int i = 1; i <= 10; i++)
std::puts(Jo(i, " * ", i+1, " = ", i*i+i));
return 0;
}
Is there anything I can improve about those functions?
I'm especially concerned about this line: std::initializer_list<int>{(Internal::ss << p, 0)...};
It looks a bit dirty, but I don't know any better alternative.
Jo() stands for "Join". The name is shortened on purpose, because this function is used very often.
That's not a good reason, you really, really don't want to do that. \$\endgroup\$std::string
around until the call to C api ends? Could you provide an example usage with C api? \$\endgroup\$const char *
string. Yes, I could keepstd::string
around, but why would I do that if my option is shorter? \$\endgroup\$