std :: string formateo como sprintf

Tengo que formatear std::string con sprintf y enviarlo al flujo de archivos. ¿Cómo puedo hacer esto?

No puede hacerlo directamente, porque no tiene acceso de escritura al búfer subyacente (hasta C + + 11, consulte el comentario de Dietrich Epp). Tendrás que hacerlo primero en una cadena de caracteres, y luego copiarlo en una cadena estándar:

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

Pero no estoy seguro de por qué no usarías solo un string stream? Supongo que tienes razones específicas para no solo hacer esto:

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

Solución C ++ 11 que usa vsnprintf() internamente:

 #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; } 

Un enfoque más seguro y eficiente (lo probé y es más rápido):

 #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()); } 

El fmt_str se pasa por valor para cumplir con los requisitos de va_start .

NOTA: La versión “más segura” y “más rápida” no funciona en algunos sistemas. Por lo tanto, ambos siguen en la lista. Además, “más rápido” depende completamente de que el paso de preasignación sea correcto, de lo contrario, strcpy hace más lento.

Utilizando C ++ 11 std::snprintf , esto se convierte en una tarea bastante fácil y segura. Veo muchas respuestas sobre esta pregunta que aparentemente fueron escritas antes del tiempo de C ++ 11, que usan longitudes y vargs de búfer fijos, algo que no recomendaría por razones de seguridad, eficiencia y claridad.

 #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 } 

El fragmento de código anterior está autorizado bajo CC0 1.0 .

Explicación línea por línea:

Objetivo: Escribir en un char* usando std::snprintf y luego convertirlo a std::string .

Primero, determinamos la longitud deseada de la matriz de caracteres.

De cppreference.com :

Valor de retorno

[…] Si la cadena resultante se trunca debido al límite buf_size, la función devuelve el número total de caracteres (sin incluir el byte nulo de terminación) que se habría escrito, si el límite no se impuso.

Esto significa que el tamaño deseado es el número de caracteres más uno , de modo que el terminador nulo se sentará después de todos los demás caracteres y que el constructor de cadenas lo puede cortar nuevamente. Este problema fue explicado por @ alexk7 en los comentarios.

Luego, asignamos una nueva matriz de caracteres y la asignamos a std::unique_ptr . En general, se recomienda esto, ya que no tendrá que delete manualmente de nuevo.

Tenga en cuenta que esta no es una forma segura de asignar un unique_ptr con tipos definidos por el usuario, ya que no puede desasignar la memoria si el constructor lanza una excepción.

Después de eso, podemos simplemente usar snprintf para su uso previsto y escribir la cadena formateada en el char[] y luego crear y devolver una nueva std::string partir de eso.


Puedes ver un ejemplo en acción aquí .


Si también desea usar std::string en la lista de argumentos, eche un vistazo a esta idea .


Información adicional para usuarios de Visual Studio :

Como se explica en esta respuesta , Microsoft renombró std::snprintf a _snprintf (sí, sin std:: _snprintf . MS además lo establece como obsoleto y aconseja usar _snprintf_s en _snprintf_s lugar, sin embargo _snprintf_s no aceptará que el búfer sea cero o más pequeño que la salida formateada y no calculará la longitud de las salidas si eso ocurre. Por lo tanto, para deshacerse de las advertencias de degradación durante la comstackción, puede insertar la siguiente línea en la parte superior del archivo que contiene el uso de _snprintf :

 #pragma warning(disable : 4996) 

boost::format() proporciona la funcionalidad que desea:

A partir de la sinopsis de las bibliotecas de formato Boost:

Un objeto de formato se construye a partir de una serie de formato, y luego se le dan argumentos a través de llamadas repetidas al operador%. Cada uno de esos argumentos se convierte en cadenas, que a su vez se combinan en una cadena, de acuerdo con la cadena de formato.

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

Desafortunadamente, la mayoría de las respuestas aquí usan varargs que son inherentemente inseguros a menos que use algo como el atributo de format de GCC que solo funciona con cadenas de formato literal. Puede ver por qué estas funciones no son seguras en el siguiente ejemplo:

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

donde string_format es una implementación de la respuesta de Erik Aronesty. Este código se comstack, pero probablemente se bloqueará cuando intente ejecutarlo:

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

Es posible implementar una printf segura y extenderla para formatear std::string usando plantillas (variadic). Esto se ha hecho en la biblioteca fmt , que proporciona una alternativa segura a sprintf std::string :

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

fmt realiza un seguimiento de los tipos de argumentos y, si el tipo no coincide con la especificación de formato, no existe un error de segmentación, solo una excepción.

Descargo de responsabilidad : soy el autor de esta biblioteca.

Si solo desea una syntax similar a printf (sin llamar a printf usted mismo), eche un vistazo al Formato Boost .

Escribí el mío usando vsnprintf así que devuelve cadena en lugar de tener que crear mi propio buffer.

 #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; } 

Entonces puedes usarlo como

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

[edit ’17 / 8/31] Agregando una variaded templated 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; } 

que es efectivamente una versión delimitada por comas (en cambio) de los operadores << veces obstaculizadores ', usados ​​así:

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

[edit] Adaptado para hacer uso de la técnica en la respuesta de Erik Aronesty (arriba):

 #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 

[respuesta anterior]
Una respuesta muy tardía, pero para aquellos que, como a mí, les gusta el estilo 'sprintf': he escrito y estoy usando las siguientes funciones. Si te gusta, puedes expandir las opciones% para que se ajusten mejor a las de sprintf; los que están ahí actualmente son suficientes para mis necesidades. Usas stringf () y stringfappend () del mismo modo que lo harías con sprintf. Solo recuerde que los parámetros para ... deben ser tipos POD.

 //============================================================================= 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 

Para formatear std::string de una manera ‘sprintf’, llame a snprintf (argumentos nullptr y 0 ) para obtener la longitud de buffer necesaria. Escribe tu función usando la plantilla variadica C ++ 11 de esta manera:

 #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); } 

Comstackr con compatibilidad con C ++ 11, por ejemplo en GCC: g++ -std=c++11

Uso:

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

Así es como lo hace google: StringPrintf (Licencia BSD)
y Facebook lo hace de una manera bastante similar: StringPrintf (Licencia de Apache)
Ambos proporcionan un StringAppendF conveniente también.

Mis dos centavos en esta pregunta tan popular.

Para citar la página de manual de las funciones tipo printf :

Tras el retorno exitoso, estas funciones devuelven la cantidad de caracteres impresos (excluyendo el byte nulo utilizado para finalizar la salida a las cadenas).

Las funciones snprintf () y vsnprintf () no escriben más bytes de tamaño (incluido el byte nulo de terminación (‘\ 0’)). Si la salida se truncó debido a este límite, entonces el valor de retorno es la cantidad de caracteres (excluyendo el byte nulo de terminación) que se habría escrito en la cadena final si hubiera suficiente espacio disponible. Por lo tanto, un valor de retorno de tamaño o más significa que la salida se truncó.

En otras palabras, una implementación sensata de C ++ 11 debe ser la siguiente:

 #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); } 

Funciona bastante bien 🙂

Las plantillas variables son compatibles solo con C ++ 11. La respuesta desde pixelpoint muestra una técnica similar usando estilos de progtwigción más antiguos.

Es extraño que C ++ no tenga una cosa así fuera de la caja. Recientemente agregaron to_string() , que en mi opinión es un gran paso adelante. Me pregunto si agregarán un operador .format a std::string eventualmente …

Editar

Como señaló alexk7, se necesita A +1 en el valor de retorno de std::snprintf , ya que necesitamos espacio para el byte \0 . Intuitivamente, en la mayoría de las architectures que faltan, el +1 hará que el entero required se sobrescriba parcialmente con un 0 . Esto sucederá después de la evaluación del parámetro required como real para std::snprintf , por lo que el efecto no debería ser visible.

Sin embargo, este problema podría cambiar, por ejemplo, con la optimización del comstackdor: ¿qué ocurre si el comstackdor decide usar un registro para la variable required ? Este es el tipo de errores que a veces resultan en problemas de seguridad.

Basado en la respuesta proporcionada por 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(); } 

Esto evita la necesidad de descartar const del resultado de .c_str() que estaba en la respuesta original.

 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; } 

Usando C99 snprintf y 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 no tiene lo que necesita, pero std :: stringstream sí lo tiene. Usa un stringstream para crear la cadena y luego extrae la cadena. Aquí hay una lista completa de las cosas que puede hacer. Por ejemplo:

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

le dará 10 decimales de precisión al imprimir un doble o flotar.

Puedes intentar esto:

 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 ); 

Probado, Respuesta de calidad de producción

 #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; } 

Este es el código que uso para hacer esto en mi progtwig … No es nada sofisticado, pero cumple la función … Tenga en cuenta que tendrá que ajustar su tamaño según corresponda. MAX_BUFFER para mí es 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; } 

Tomó la idea de Dacav y la respuesta de pixelpoint . Jugué un poco y obtuve esto:

 #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); } 

Con una práctica de progtwigción sensata, creo que el código debería ser suficiente, sin embargo, todavía estoy abierto a alternativas más seguras que aún son lo suficientemente simples y que no requerirían C ++ 11.


Y aquí hay otra versión que hace uso de un buffer inicial para evitar una segunda llamada a vsnprintf() cuando el buffer inicial ya es suficiente.

 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); } 

(Resulta que esta versión es similar a la respuesta de Piti Ongmongkolkul , solo que no usa new y delete[] , y también especifica un tamaño al crear std::string .

La idea aquí de no usar new y delete[] es implicar el uso de la stack sobre el montón ya que no necesita llamar a las funciones de asignación y desasignación, sin embargo, si no se usa adecuadamente, podría ser peligroso desbordamientos de búfer en algunos ( quizás sistemas viejos, o quizás solo vulnerables). Si esto es una preocupación, le sugiero usar new y delete[] lugar. Tenga en cuenta que la única preocupación aquí es acerca de las asignaciones ya que vsnprintf() ya se llama con límites, por lo que especificar un límite basado en el tamaño asignado en el segundo búfer también lo evitaría.

Usualmente uso esto:

 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; } 

Desventaja: no todos los sistemas admiten 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"; } 

Salida:

 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; 

Salida:

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();