std :: string Formatierung wie sprintf

Ich muss std::string mit sprintf und es in den Dateistream senden. Wie kann ich das machen?

Sie können es nicht direkt tun, weil Sie keinen Schreibzugriff auf den zugrunde liegenden Puffer haben (bis C ++ 11; siehe Kommentar von Dietrich Epp). Sie müssen es zuerst in einer C-Zeichenfolge tun, dann kopieren Sie es in eine Std :: string:

  char buff[100]; snprintf(buff, sizeof(buff), "%s", "Hello"); std::string buffAsStdStr = buff; 

Aber ich bin mir nicht sicher, warum Sie nicht einfach einen String-Stream verwenden würden? Ich nehme an, Sie haben bestimmte Gründe, dies nicht nur zu tun:

  std::ostringstream stringStream; stringStream < < "Hello"; std::string copyOfStr = stringStream.str(); 

C ++ 11-Lösung, die vsnprintf() intern verwendet:

 #include  // For va_start, etc. std::string string_format(const std::string fmt, ...) { int size = ((int)fmt.size()) * 2 + 50; // Use a rubric appropriate for your code std::string str; va_list ap; while (1) { // Maximum two passes on a POSIX system... str.resize(size); va_start(ap, fmt); int n = vsnprintf((char *)str.data(), size, fmt.c_str(), ap); va_end(ap); if (n > -1 && n < size) { // Everything worked str.resize(n); return str; } if (n > -1) // Needed size returned size = n + 1; // For null char else size *= 2; // Guess at a larger size (OS specific) } return str; } 

Ein sicherer und effizienter (ich habe es getestet, und es ist schneller) Ansatz:

 #include  // For va_start, etc. #include  // For std::unique_ptr std::string string_format(const std::string fmt_str, ...) { int final_n, n = ((int)fmt_str.size()) * 2; /* Reserve two times as much as the length of the fmt_str */ std::unique_ptr formatted; va_list ap; while(1) { formatted.reset(new char[n]); /* Wrap the plain char array into the unique_ptr */ strcpy(&formatted[0], fmt_str.c_str()); va_start(ap, fmt_str); final_n = vsnprintf(&formatted[0], n, fmt_str.c_str(), ap); va_end(ap); if (final_n < 0 || final_n >= n) n += abs(final_n - n + 1); else break; } return std::string(formatted.get()); } 

Der Wert fmt_str wird als Wert übergeben, um den Anforderungen von va_start .

Hinweis: die “sicherere” und “schnellere” Version funktioniert auf einigen Systemen nicht. Daher sind beide noch aufgelistet. Auch “schneller” hängt vollständig davon ab, dass der Vor-Zuordnungsschritt korrekt ist, andernfalls macht das ” strcpy es langsamer.

Mit C ++ 11 std::snprintf wird dies zu einer ziemlich einfachen und sicheren Aufgabe. Ich sehe viele Antworten auf diese Frage, die anscheinend vor der Zeit von C ++ 11 geschrieben wurden, die feste Pufferlängen und vargs verwenden, etwas, das ich aus Gründen der Sicherheit, Effizienz und Klarheit nicht empfehlen würde.

 #include  #include  #include  #include  using namespace std; //Don't if you're in a header-file template string string_format( const std::string& format, Args ... args ) { size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0' unique_ptr buf( new char[ size ] ); snprintf( buf.get(), size, format.c_str(), args ... ); return string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside } 

Das obige Code-Snippet ist unter CC0 1.0 lizenziert.

Zeile für Zeile Erklärung:

Ziel: Schreiben Sie in ein char* indem Sie std::snprintf und konvertieren Sie das dann in eine std::string .

Zuerst bestimmen wir die gewünschte Länge des Char-Arrays.

Aus cppreference.com :

Rückgabewert

[…] Wenn die resultierende Zeichenkette aufgrund von buf_size limit abgeschnitten wird, gibt function die Gesamtzahl der Zeichen (ohne das abschließende Nullbyte) zurück, die geschrieben worden wären, wenn das Limit nicht auferlegt worden wäre.

Dies bedeutet, dass die gewünschte Größe die Anzahl der Zeichen plus eins ist , so dass der Null-Terminator hinter allen anderen Zeichen steht und dass er vom String-Konstruktor wieder abgeschnitten werden kann. Dieses Problem wurde von @ alexk7 in den Kommentaren erläutert.

Dann weisen wir ein neues Zeichen-Array zu und weisen es einem std::unique_ptr . Dies wird allgemein empfohlen, da Sie es nicht erneut manuell delete .

Beachten Sie, dass dies keine sichere Methode ist, unique_ptr mit benutzerdefinierten Typen zuzuweisen, da Sie den Speicher nicht freigeben können, wenn der Konstruktor eine Ausnahme austriggers!

Danach können wir natürlich einfach snprintf für die beabsichtigte Verwendung verwenden und die formatierte Zeichenfolge in char[] schreiben und danach eine neue std::string daraus erstellen und zurückgeben.


Sie können hier ein Beispiel in Aktion sehen .


Wenn Sie auch std::string in der Argumentenliste verwenden möchten, sehen Sie sich diesen Text an .


Zusätzliche Informationen für Visual Studio- Benutzer:

Wie in dieser Antwort erklärt , hat Microsoft std::snprintf in _snprintf (ja, ohne std:: _snprintf . MS setzt es weiter als veraltet und rät, _snprintf_s stattdessen zu verwenden, jedoch akzeptiert _snprintf_s den Puffer nicht als null oder kleiner als die formatierte Ausgabe und berechnet die Ausgabenlänge nicht, wenn dies auftritt. Um die Verwarnungswarnungen während der Kompilierung loszuwerden, können Sie die folgende Zeile am Anfang der Datei einfügen, die die Verwendung von _snprintf :

 #pragma warning(disable : 4996) 

boost::format() bietet die gewünschte functionalität:

Wie aus den Boost-Format-Bibliotheken:

Ein Format-Objekt wird aus einer Format-Zeichenfolge konstruiert und erhält dann Argumente durch wiederholte Aufrufe von Operator%. Jedes dieser Argumente wird dann in Zeichenfolgen konvertiert, die wiederum gemäß der Formatzeichenfolge zu einer Zeichenfolge zusammengefasst werden.

 #include  cout < < boost::format("writing %1%, x=%2% : %3%-th try") % "toto" % 40.23 % 50; // prints "writing toto, x=40.230 : 50-th try" 

Leider verwenden die meisten Antworten hier varargs, die von Natur aus unsicher sind, es sei denn, Sie verwenden etwas wie das Formatattribut von GCC, das nur mit literalen Formatzeichenfolgen arbeitet. Sie können im folgenden Beispiel sehen, warum diese functionen nicht sicher sind:

 std::string format_str = "%s"; string_format(format_str, format_str[0]); 

where string_format ist eine Implementierung aus der Antwort der Erik Aronesty. Dieser Code wird kompiliert, wird aber höchstwahrscheinlich abstürzen, wenn Sie versuchen, ihn auszuführen:

 $ g++ -Wall -Wextra -pedantic test.cc $ ./a.out Segmentation fault: 11 

Es ist möglich, ein sicheres printf zu implementieren und es zu erweitern, um std::string Verwendung von (variadic) Vorlagen zu formatieren. Dies wurde in der fmt-Bibliothek getan, die eine sichere Alternative zu sprintf bietet, die std::string sprintf :

 std::string format_str = "The answer is %d"; std::string result = fmt::sprintf(format_str, 42); 

fmt verfolgt die Argumenttypen und wenn der Typ nicht der Formatspezifikation entspricht, gibt es keinen Segmentierungserrors, nur eine Ausnahme.

Haftungsausschluss : Ich bin der Autor dieser Bibliothek.

Wenn Sie nur eine printf-ähnliche Syntax wünschen (ohne printf selbst aufzurufen), schauen Sie sich das Boost Format an .

Ich schrieb mein eigenes mit vsnprintf, so dass es String zurückgibt, anstatt meinen eigenen Puffer zu erstellen.

 #include  #include  //missing string printf //this is safe and convenient but not exactly efficient inline std::string format(const char* fmt, ...){ int size = 512; char* buffer = 0; buffer = new char[size]; va_list vl; va_start(vl, fmt); int nsize = vsnprintf(buffer, size, fmt, vl); if(size< =nsize){ //fail delete buffer and try again delete[] buffer; buffer = 0; buffer = new char[nsize+1]; //+1 for /0 nsize = vsnprintf(buffer, size, fmt, vl); } std::string ret(buffer); va_end(vl); delete[] buffer; return ret; } 

Du kannst es also gerne benutzen

 std::string mystr = format("%s %d %10.5f", "omg", 1, 10.5); 

[Bearbeiten ’17 / 8/31] Hinzufügen einer variantenbasierten Version ‘vtspf (..)’:

 template const std::string type_to_string(const T &v) { std::ostringstream ss; ss < < v; return ss.str(); }; template const T string_to_type(const std::string &str) { std::istringstream ss(str); T ret; ss >> ret; return ret; }; template void vtspf_priv(std::string &s) {} template void vtspf_priv(std::string &s, H h, P...p) { s+=type_to_string(h); vtspf_priv(s, p...); } template std::string temp_vtspf(P...p) { std::string s(""); vtspf_priv(s, p...); return s; } 

Das ist effektiv eine Komma-begrenzte Version (stattdessen) der manchmal behindernden < < -Operatoren, verwendet wie folgt:

 char chSpace=' '; double pi=3.1415; std::string sWorld="World", str_var; str_var = vtspf("Hello", ',', chSpace, sWorld, ", pi=", pi); 

[Bearbeiten] Angepasst, um die Technik in Erik Aronestys Antwort zu nutzen (oben):

 #include  #include  #include  //============================================================================= void spf(std::string &s, const std::string fmt, ...) { int n, size=100; bool b=false; va_list marker; while (!b) { s.resize(size); va_start(marker, fmt); n = vsnprintf((char*)s.c_str(), size, fmt.c_str(), marker); va_end(marker); if ((n>0) && ((b=(n0) && ((b=(n 

[vorherige Antwort]
Eine sehr späte Antwort, aber für diejenigen, die wie ich den Sprint-Weg mögen: Ich habe geschrieben und benutze die folgenden functionen. Wenn es Ihnen gefällt, können Sie die% -Optionen erweitern, um den Sprintf-Werten besser zu entsprechen. Die dort sind derzeit ausreichend für meine Bedürfnisse. Sie verwenden stringf () und stringfappend () genauso wie Sie sprintf. Denken Sie daran, dass die Parameter für ... POD-Typen sein müssen.

 //============================================================================= void DoFormatting(std::string& sF, const char* sformat, va_list marker) { char *s, ch=0; int n, i=0, m; long l; double d; std::string sf = sformat; std::stringstream ss; m = sf.length(); while (i 

Um std::string in einer “sprintf” -Methode zu formatieren, rufen Sie snprintf (Argumente nullptr und 0 ) auf, um die Länge des benötigten Puffers zu erhalten. Schreiben Sie Ihre function mit C ++ 11 variadic Vorlage wie folgt:

 #include  #include  #include  template< typename... Args > std::string string_sprintf( const char* format, Args... args ) { int length = std::snprintf( nullptr, 0, format, args... ); assert( length >= 0 ); char* buf = new char[length + 1]; std::snprintf( buf, length + 1, format, args... ); std::string str( buf ); delete[] buf; return std::move(str); } 

Kompilieren Sie mit C ++ 11 Unterstützung, zum Beispiel in GCC: g++ -std=c++11

Verwendung:

  std::cout < < string_sprintf("%g, %g\n", 1.23, 0.001); 

So macht es Google: StringPrintf (BSD-Lizenz)
und Facebook macht es in einer ziemlich ähnlichen Weise: StringPrintf (Apache-Lizenz)
Beide bieten auch einen praktischen StringAppendF .

Meine zwei Cent bei dieser sehr beliebten Frage.

Um die Manpage von printf ähnlichen functionen zu zitieren:

Bei erfolgreicher Rückgabe geben diese functionen die Anzahl der gedruckten Zeichen zurück (mit Ausnahme des Nullbytes, das zum Beenden der Ausgabe an Zeichenfolgen verwendet wird).

Die functionen snprintf () und vsnprintf () schreiben nicht mehr als Größe Bytes (einschließlich des abschließenden Nullbyte (‘\ 0’)). Wenn die Ausgabe aufgrund dieses Limits abgeschnitten wurde, ist der Rückgabewert die Anzahl der Zeichen (mit Ausnahme des abschließenden Null-Bytes), die in die letzte Zeichenfolge geschrieben worden wäre, wenn genügend Speicherplatz verfügbar gewesen wäre. Daher bedeutet ein Rückgabewert der Größe oder mehr, dass die Ausgabe abgeschnitten wurde.

Mit anderen Worten, eine vernünftige C ++ 11 Implementierung sollte die folgende sein:

 #include  #include  template  std::string fmt (const std::string &fmt, Ts... vs) { char b; size_t required = std::snprintf(&b, 0, fmt.c_str(), vs...) + 1; // See comments: the +1 is necessary, while the first parameter // can also be set to nullptr char bytes[required]; std::snprintf(bytes, required, fmt.c_str(), vs...); return std::string(bytes); } 

Es funktioniert ganz gut 🙂

Variadic Vorlagen werden nur in C ++ 11 unterstützt. Die Antwort von Pixelpoint zeigt eine ähnliche Technik mit älteren Programmierstilen.

Es ist komisch, dass C ++ so etwas nicht hat. Sie haben vor kurzem to_string() hinzugefügt, was meiner Meinung nach einen großen Schritt vorwärts ist. Ich frage mich, ob sie der std::string irgendwann einen .format Operator hinzufügen …

Bearbeiten

Wie alexk7 darauf hingewiesen hat, wird A +1 für den Rückgabewert von std::snprintf , da wir Platz für das \0 Byte haben müssen. Intuitiv führt das Fehlen der +1 bei den meisten Architekturen dazu, dass die required ganze Zahl teilweise mit einer 0 überschrieben wird. Dies geschieht nach der Auswertung des als Aktualparameter für std::snprintf required Parameters, damit der Effekt nicht sichtbar sein sollte.

Dieses Problem könnte sich jedoch ändern, zum Beispiel bei der Compiler-Optimierung: Was ist, wenn der Compiler beschließt, ein Register für die required Variable zu verwenden? Dies ist die Art von Fehlern, die manchmal zu Sicherheitsproblemen führen.

Basierend auf der Antwort von Erik Aronesty:

 std::string string_format(const std::string &fmt, ...) { std::vector str(100,'\0'); va_list ap; while (1) { va_start(ap, fmt); auto n = vsnprintf(str.data(), str.size(), fmt.c_str(), ap); va_end(ap); if ((n > -1) && (size_t(n) < str.size())) { return str.data(); } if (n > -1) str.resize( n + 1 ); else str.resize( str.size() * 2); } return str.data(); } 

Dies vermeidet die Notwendigkeit, const aus dem Ergebnis von .c_str() das in der ursprünglichen Antwort enthalten war, .c_str() .

 template std::string string_format(const char* fmt, Args... args) { size_t size = snprintf(nullptr, 0, fmt, args...); std::string buf; buf.reserve(size + 1); buf.resize(size); snprintf(&buf[0], size + 1, fmt, args...); return buf; } 

Verwenden von C99 snprintf und C ++ 11

 inline void format(string& a_string, const char* fmt, ...) { va_list vl; va_start(vl, fmt); int size = _vscprintf( fmt, vl ); a_string.resize( ++size ); vsnprintf_s((char*)a_string.data(), size, _TRUNCATE, fmt, vl); va_end(vl); } 

string hat nicht das was du brauchst, aber std :: stringstream tut es. Verwenden Sie einen Stringstream, um die Zeichenfolge zu erstellen, und extrahieren Sie dann die Zeichenfolge. Hier finden Sie eine umfassende Liste der Dinge, die Sie tun können. Beispielsweise:

 cout.setprecision(10); //stringstream is a stream like cout 

gibt Ihnen 10 Dezimalstellen der Genauigkeit beim Drucken eines Doppelten oder Flosses.

Du könntest das versuchen:

 string str; str.resize( _MAX_PATH ); sprintf( &str[0], "%s %s", "hello", "world" ); // optionals // sprintf_s( &str[0], str.length(), "%s %s", "hello", "world" ); // Microsoft // #include  // snprintf( &str[0], str.length(), "%s %s", "hello", "world" ); // c++11 str.resize( strlen( str.data() ) + 1 ); 

Getestet, Produktionsqualität Antwort

 #include  #include  #include  // requires at least C++11 const std::string vformat(const char * const zcFormat, ...) { // initialize use of the variable argument array va_list vaArgs; va_start(vaArgs, zcFormat); // reliably acquire the size // from a copy of the variable argument array // and a functionally reliable call to mock the formatting va_list vaArgsCopy; va_copy(vaArgsCopy, vaArgs); const int iLen = std::vsnprintf(NULL, 0, zcFormat, vaArgsCopy); va_end(vaArgsCopy); // return a formatted string without risking memory mismanagement // and without assuming any compiler or platform specific behavior std::vector zc(iLen + 1); std::vsnprintf(zc.data(), zc.size(), zcFormat, vaArgs); va_end(vaArgs); return std::string(zc.data(), iLen); } #include  #include  #include  // demonstration of use int main() { std::time_t t = std::time(nullptr); std::cerr < < std::put_time(std::localtime(& t), "%D %T") << " [debug]: " << vformat("Int 1 is %d, Int 2 is %d, Int 3 is %d", 11, 22, 33) << std::endl; return 0; } 

Dies ist der Code, den ich in meinem Programm verwende … Es ist nichts Schickes, aber es macht den Trick … Beachten Sie, dass Sie Ihre Größe entsprechend anpassen müssen. MAX_BUFFER ist für mich 1024.

 std::string Format ( const char *fmt, ... ) { char textString[MAX_BUFFER*5] = {'\0'}; // -- Empty the buffer properly to ensure no leaks. memset(textString, '\0', sizeof(textString)); va_list args; va_start ( args, fmt ); vsnprintf ( textString, MAX_BUFFER*5, fmt, args ); va_end ( args ); std::string retStr = textString; return retStr; } 

Nahm die Idee von Dacav und pixelpoints Antwort . Ich habe ein bisschen herumgespielt und folgendes bekommen:

 #include  #include  #include  std::string format(const char* fmt, ...) { va_list vl; va_start(vl, fmt); int size = vsnprintf(0, 0, fmt, vl) + sizeof('\0'); va_end(vl); char buffer[size]; va_start(vl, fmt); size = vsnprintf(buffer, size, fmt, vl); va_end(vl); return std::string(buffer, size); } 

Mit vernünftiger Programmierpraxis glaube ich, dass der Code ausreichen sollte, aber ich bin immer noch offen für sicherere Alternativen, die immer noch einfach genug sind und C ++ 11 nicht benötigen.


Und hier ist eine andere Version, die einen Anfangspuffer verwendet, um den zweiten Aufruf von vsnprintf() zu verhindern, wenn der Anfangspuffer bereits ausreicht.

 std::string format(const char* fmt, ...) { va_list vl; int size; enum { INITIAL_BUFFER_SIZE = 512 }; { char buffer[INITIAL_BUFFER_SIZE]; va_start(vl, fmt); size = vsnprintf(buffer, INITIAL_BUFFER_SIZE, fmt, vl); va_end(vl); if (size < INITIAL_BUFFER_SIZE) return std::string(buffer, size); } size += sizeof('\0'); char buffer[size]; va_start(vl, fmt); size = vsnprintf(buffer, size, fmt, vl); va_end(vl); return std::string(buffer, size); } 

(Es stellt sich heraus, dass diese Version der Antwort von Piti Ongmongkolkul nur ähnlich ist , nur dass sie new und delete[] nicht verwendet und beim Erstellen von std::string auch eine Größe angibt.

Die Idee hier, new und delete[] ist die Verwendung des Stapels über den Heap, da es keine Zuweisungs- und Freigabe-functionen aufrufen muss. Wenn es jedoch nicht richtig verwendet wird, könnte es gefährlich sein, Pufferüberläufe in einigen ( vielleicht alte oder vielleicht nur verwundbare Systeme. Wenn dies ein Problem ist, empfehle ich sehr, stattdessen new und delete[] verwenden. Beachten Sie, dass hier nur die Zuweisungen behandelt werden, da vsnprintf() bereits mit Begrenzungen aufgerufen wird. vsnprintf() Angeben eines Limits auf der Basis der Größe, die auf dem zweiten Puffer zugewiesen wurde, auch diese verhindern.)

Ich benutze das normalerweise:

 std::string myformat(const char *const fmt, ...) { char *buffer = NULL; va_list ap; va_start(ap, fmt); (void)vasprintf(&buffer, fmt, ap); va_end(ap); std::string result = buffer; free(buffer); return result; } 

Nachteil: Nicht alle Systeme unterstützen vasprint

If you are on a system that has asprintf(3) , you can easily wrap it:

 #include  #include  #include  std::string format(const char *fmt, ...) __attribute__ ((format (printf, 1, 2))); std::string format(const char *fmt, ...) { std::string result; va_list ap; va_start(ap, fmt); char *tmp = 0; int res = vasprintf(&tmp, fmt, ap); va_end(ap); if (res != -1) { result = tmp; free(tmp); } else { // The vasprintf call failed, either do nothing and // fall through (will return empty string) or // throw an exception, if your code uses those } return result; } int main(int argc, char *argv[]) { std::string username = "you"; std::cout < < format("Hello %s! %d", username.c_str(), 123) << std::endl; return 0; } 

Very-very simple solution.

 std::string strBuf; strBuf.resize(256); int iCharsPrinted = sprintf_s((char *)strPath.c_str(), strPath.size(), ...); strBuf.resize(iCharsPrinted); 

Below slightly modified version of @iFreilicht answer, updated to C++14 (usage of make_unique function instead of raw declaration) and added support for std::string arguments (based on Kenny Kerr article )

 #include  #include  #include  #include  template  T process_arg(T value) noexcept { return value; } template  T const * process_arg(std::basic_string const & value) noexcept { return value.c_str(); } template std::string string_format(const std::string& format, Args const & ... args) { const auto fmt = format.c_str(); const size_t size = std::snprintf(nullptr, 0, fmt, process_arg(args) ...) + 1; auto buf = std::make_unique(size); std::snprintf(buf.get(), size, fmt, process_arg(args) ...); auto res = std::string(buf.get(), buf.get() + size - 1); return res; } int main() { int i = 3; float f = 5.f; char* s0 = "hello"; std::string s1 = "world"; std::cout < < string_format("i=%d, f=%f, s=%s %s", i, f, s0, s1) << "\n"; } 

Ausgabe:

 i = 3, f = 5.000000, s = hello world 

Feel free to merge this answer with the original one if desired.

One solution I’ve favoured is to do this with sprintf directly into the std::string buffer, after making said buffer big enough:

 #include  #include  using namespace std; string l_output; l_output.resize(100); for (int i = 0; i < 1000; ++i) { memset (&l_output[0], 0, 100); sprintf (&l_output[0], "\r%i\0", i); cout << l_output; cout.flush(); } 

So, create the std::string, resize it, access its buffer directly...

Poco Foundation library has a very convenient format function, which supports std::string in both the format string and the values:

You can format C++ output in cout using iomanip header file. Make sure that you include iomanip header file before you use any of the helper functions like setprecision, setfill etc.

Here is a code snippet I have used in the past to print the average waiting time in the vector, which I have “accumulated”.

 #include #include #include #include ... cout< < "Average waiting times for tasks is " << setprecision(4) << accumulate(all(waitingTimes), 0)/double(waitingTimes.size()) ; cout << " and " << Q.size() << " tasks remaining" << endl; 

Here is a brief description of how we can format C++ streams. http://www.cprogramming.com/tutorial/iomanip.html

There can be problems, if the buffer is not large enough to print the string. You must determine the length of the formatted string before printing a formatted message in there. I make own helper to this (tested on Windows and Linux GCC ), and you can try use it.

String.cpp: http://pastebin.com/DnfvzyKP
String.h: http://pastebin.com/7U6iCUMa

String.cpp:

 #include  #include  #include  #include  using ::std::string; #pragma warning(disable : 4996) #ifndef va_copy #ifdef _MSC_VER #define va_copy(dst, src) dst=src #elif !(__cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)) #define va_copy(dst, src) memcpy((void*)dst, (void*)src, sizeof(*src)) #endif #endif /// /// \breif Format message /// \param dst String to store formatted message /// \param format Format of message /// \param ap Variable argument list /// void toString(string &dst, const char *format, va_list ap) throw() { int length; va_list apStrLen; va_copy(apStrLen, ap); length = vsnprintf(NULL, 0, format, apStrLen); va_end(apStrLen); if (length > 0) { dst.resize(length); vsnprintf((char *)dst.data(), dst.size() + 1, format, ap); } else { dst = "Format error! format: "; dst.append(format); } } /// /// \breif Format message /// \param dst String to store formatted message /// \param format Format of message /// \param ... Variable argument list /// void toString(string &dst, const char *format, ...) throw() { va_list ap; va_start(ap, format); toString(dst, format, ap); va_end(ap); } /// /// \breif Format message /// \param format Format of message /// \param ... Variable argument list /// string toString(const char *format, ...) throw() { string dst; va_list ap; va_start(ap, format); toString(dst, format, ap); va_end(ap); return dst; } /// /// \breif Format message /// \param format Format of message /// \param ap Variable argument list /// string toString(const char *format, va_list ap) throw() { string dst; toString(dst, format, ap); return dst; } int main() { int a = 32; const char * str = "This works!"; string test(toString("\nSome testing: a = %d, %s\n", a, str)); printf(test.c_str()); a = 0x7fffffff; test = toString("\nMore testing: a = %d, %s\n", a, "This works too.."); printf(test.c_str()); a = 0x80000000; toString(test, "\nMore testing: a = %d, %s\n", a, "This way is cheaper"); printf(test.c_str()); return 0; } 

String.h:

 #pragma once #include  #include  using ::std::string; /// /// \breif Format message /// \param dst String to store formatted message /// \param format Format of message /// \param ap Variable argument list /// void toString(string &dst, const char *format, va_list ap) throw(); /// /// \breif Format message /// \param dst String to store formatted message /// \param format Format of message /// \param ... Variable argument list /// void toString(string &dst, const char *format, ...) throw(); /// /// \breif Format message /// \param format Format of message /// \param ... Variable argument list /// string toString(const char *format, ...) throw(); /// /// \breif Format message /// \param format Format of message /// \param ap Variable argument list /// string toString(const char *format, va_list ap) throw(); 

I gave it a try, with regular expressions . I implemented it for ints and const strings as an example, but you can add whatever other types ( POD types but with pointers you can print anything).

 #include  #include  #include  #include  #include  static std::string formatArg(std::string argDescr, va_list args) { std::stringstream ss; if (argDescr == "i") { int val = va_arg(args, int); ss < < val; return ss.str(); } if (argDescr == "s") { const char *val = va_arg(args, const char*); ss << val; return ss.str(); } assert(0); //Not implemented } std::string format(std::string fmt, ...) { std::string result(fmt); va_list args; va_start(args, fmt); std::regex e("\\{([^\\{\\}]+)\\}"); std::smatch m; while (std::regex_search(fmt, m, e)) { std::string formattedArg = formatArg(m[1].str(), args); fmt.replace(m.position(), m.length(), formattedArg); } va_end(args); return fmt; } 

Here is an example of use of it:

 std::string formatted = format("I am {s} and I have {i} cats", "bob", 3); std::cout < < formatted << std::endl; 

Ausgabe:

I am bob and I have 3 cats

this can be tried out. simple. really does not use nuances of the string class though.

 #include  #include  #include  #include  #include  #include  using namespace std; //--------------------------------------------------------------------- class StringFormatter { public: static string format(const char *format, ...); }; string StringFormatter::format(const char *format, ...) { va_list argptr; va_start(argptr, format); char *ptr; size_t size; FILE *fp_mem = open_memstream(&ptr, &size); assert(fp_mem); vfprintf (fp_mem, format, argptr); fclose (fp_mem); va_end(argptr); string ret = ptr; free(ptr); return ret; } //--------------------------------------------------------------------- int main(void) { string temp = StringFormatter::format("my age is %d", 100); printf("%s\n", temp.c_str()); return 0; } 
 _return.desc = (boost::format("fail to detect. cv_result = %d") % st_result).str();