You can write a utility function to build a std::string from a printf-style format:
#include <cstdio>
#include <cstdarg>
#include <string>
#include <vector>
std::string build_string(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
size_t len = vsnprintf(NULL, 0, fmt, args);
va_end(args);
std::vector<char> vec(len + 1);
va_start(args, fmt);
vsnprintf(vec.data(), len + 1, fmt, args);
va_end(args);
return std::string(vec.begin(), vec.end() - 1);
}
With this function in place, you can create arbitrary strings and pass pointers to their contents as downward-arguments:
MessageBoxA(0, build_string("You have %d items", item_count).c_str(), "title", 0);
It has the advantage of simplicity (several lines of code using only stdio without dependency on iostreams), and has no arbitrary limits on the size of string.