i think in std c++11 or 17 dan.tilley answer is the most idiomatic, and pachde’s is very friendly to C devs - and a good way to implement snprintf like api on std::strings (although should that std::min be r+1 to account for the null terminator? I think the return value of vsnprintf is chars without the null).
in c++20 the language introduces std::format
and its a way better API, just it requires c++20. But luckily the library has been ported to prior versions here. We adopted that a couple of years ago, use it for new code, and have been slowly back-porting old code to it. It’s faster and safer than sprintf and way less clumsy the stream api.
Hope that helps!