formatação std :: string como sprintf

Eu tenho que formatar std::string com sprintf e enviá-lo para o stream de arquivos. Como posso fazer isso?

Você não pode fazer isso diretamente, porque você não tem access de gravação ao buffer subjacente (até C ++ 11; veja o comentário de Dietrich Epp). Você terá que fazer isso primeiro em uma string C e copiá-lo em uma string std:

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

Mas não sei por que você não usaria apenas um stream de strings? Eu estou supondo que você tenha razões específicas para não apenas fazer isso:

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

Solução 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; } 

Uma abordagem mais segura e eficiente (testei e é mais rápida):

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

O fmt_str é passado por valor para estar em conformidade com os requisitos de va_start .

NOTA: A versão “mais segura” e “mais rápida” não funciona em alguns sistemas. Portanto, ambos ainda estão listados. Além disso, “mais rápido” depende inteiramente da etapa de pré-alocação estar correta, caso contrário, o strcpy torna mais lento.

Utilizando o C ++ 11 std::snprintf , isso se torna uma tarefa bastante fácil e segura. Eu vejo um monte de respostas sobre esta questão que foram aparentemente escritas antes do tempo de C + + 11, que usam comprimentos de buffer fixo e vargs, algo que eu não recomendaria por razões de segurança, eficiência e clareza.

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

O snippet de código acima está licenciado sob CC0 1.0 .

Explicação linha por linha:

Objetivo: Escreva para um char* usando std::snprintf e então converta isso para std::string .

Primeiro, determinamos o comprimento desejado da matriz de caracteres.

De cppreference.com :

Valor de retorno

[…] Se a string resultante ficar truncada devido ao limite buf_size, a function retornará o número total de caracteres (sem include o byte nulo de terminação) que teria sido gravado, se o limite não tivesse sido imposto.

Isso significa que o tamanho desejado é o número de caracteres mais um , de modo que o terminador nulo fique posicionado depois de todos os outros caracteres e que possa ser cortado pelo construtor de string novamente. Este problema foi explicado por @ alexk7 nos comentários.

Em seguida, alocamos uma nova matriz de caracteres e a atribuímos a std::unique_ptr . Isso geralmente é recomendado, já que você não precisará delete lo manualmente novamente.

Note que esta não é uma maneira segura de alocar um unique_ptr com tipos definidos pelo usuário, pois você não pode desalocar a memory se o construtor lançar uma exceção!

Depois disso, é claro que podemos usar o snprintf para o uso pretendido e gravar a string formatada no char[] e depois criar e retornar uma nova std::string from.


Você pode ver um exemplo em ação aqui .


Se você também quiser usar std::string na lista de argumentos, dê uma olhada nesta essência .


Informações adicionais para usuários do Visual Studio :

Conforme explicado nesta resposta , a Microsoft renomeou std::snprintf para _snprintf (sim, sem std:: _snprintf . MS ainda o define como obsoleto e recomenda usar _snprintf_s , mas _snprintf_s não aceitará que o buffer seja zero ou menor que a saída formatada e não calculará o tamanho das saídas se isso ocorrer. Portanto, para se livrar dos avisos de descontinuação durante a compilation, você pode inserir a seguinte linha na parte superior do arquivo que contém o uso de _snprintf :

 #pragma warning(disable : 4996) 

boost::format() fornece a funcionalidade que você deseja:

A partir da sinopse das bibliotecas de formatos Boost:

Um object de formato é construído a partir de uma string de formato e recebe argumentos por meio de chamadas repetidas para o operador%. Cada um desses argumentos é então convertido em strings, que por sua vez são combinados em uma string, de acordo com a string de formatação.

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

Infelizmente, a maioria das respostas aqui usa varargs que são inerentemente inseguros, a menos que você use algo como o atributo de format do GCC, que só funciona com strings de formato literal. Você pode ver porque essas funções não são seguras no seguinte exemplo:

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

onde string_format é uma implementação da resposta do Erik Aronesty. Este código compila, mas provavelmente irá falhar quando você tentar executá-lo:

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

É possível implementar um printf seguro e estendê-lo para formatar std::string usando modelos (variadic). Isso foi feito na biblioteca fmt , que fornece uma alternativa segura para o sprintf retornando std::string :

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

fmt mantém o controle dos tipos de argumentos e se o tipo não corresponder à especificação de formato, não haverá falha de segmentação, apenas uma exceção.

Isenção de responsabilidade : Sou o autor desta biblioteca.

Se você quiser apenas uma syntax semelhante a printf (sem chamar o printf), dê uma olhada no Boost Format .

Eu escrevi meu próprio usando vsnprintf para que ele retorne string em vez de ter que criar meu próprio 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; } 

Então você pode usá-lo como

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

[edit ’17 / 8/31] Adicionando uma versão variada de modelo ‘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 é efetivamente uma versão delimitada por vírgula (em vez disso) dos << -operadores às vezes dificultadores, usados ​​assim:

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

[edit] Adaptado para fazer uso da técnica na resposta de Erik Aronesty (acima):

 #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 

[resposta anterior]
Uma resposta muito tardia, mas para aqueles que, como eu, gostam do modo 'sprintf': escrevi e estou usando as seguintes funções. Se você gosta, você pode expandir as opções-% para se adequar mais às sprintf; os que existem atualmente são suficientes para minhas necessidades. Você usa stringf () e stringfappend () da mesma forma que faria com sprintf. Apenas lembre-se de que os parâmetros para ... devem ser do tipo 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 formatar std::string em uma maneira ‘sprintf’, chame snprintf (arguments nullptr e 0 ) para obter o comprimento do buffer necessário. Escreva sua function usando o modelo variadic do C ++ 11 como este:

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

Compile com suporte a C ++ 11, por exemplo, no GCC: g++ -std=c++11

Uso:

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

É assim que o google faz isso: StringPrintf (Licença BSD)
e facebook faz isso de uma forma bastante similar: StringPrintf (Apache License)
Ambos fornecem também um conveniente StringAppendF .

Meus dois centavos nesta pergunta muito popular.

Para citar a manpage de funções do tipo printf :

Após o retorno bem-sucedido, essas funções retornam o número de caracteres impressos (excluindo o byte nulo usado para encerrar a saída em cadeias).

As funções snprintf () e vsnprintf () não escrevem mais que bytes de tamanho (incluindo o byte de terminação nula (‘\ 0’)). Se a saída foi truncada devido a esse limite, o valor de retorno será o número de caracteres (excluindo o byte nulo de terminação) que teria sido gravado na cadeia final se houvesse espaço suficiente disponível. Assim, um valor de retorno de tamanho ou mais significa que a saída foi truncada.

Em outras palavras, uma implementação sã de C ++ 11 deve ser a seguinte:

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

Isso funciona muito bem 🙂

Modelos Variadic são suportados apenas no C ++ 11. A resposta do ponto de pixel mostra uma técnica semelhante usando estilos de programação mais antigos.

É estranho que o C ++ não tenha essa coisa fora da checkbox. Eles recentemente adicionaram to_string() , que na minha opinião é um grande passo em frente. Eu estou querendo saber se eles irão adicionar um operador .format ao std::string eventualmente …

Editar

Como alexk7 apontou, A +1 é necessário no valor de retorno de std::snprintf , já que precisamos ter espaço para o byte \0 . Intuitivamente, na maioria das arquiteturas que perderam o +1 , o inteiro required será parcialmente substituído por um 0 . Isso acontecerá após a avaliação do required como parâmetro real para std::snprintf , portanto, o efeito não deve ser visível.

Esse problema pode, no entanto, mudar, por exemplo, com a otimização do compilador: e se o compilador decidir usar um registro para a variável required ? Esse é o tipo de erro que às vezes resulta em problemas de segurança.

Baseado na resposta fornecida 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(); } 

Isso evita a necessidade de eliminar const do resultado de .c_str() que estava na resposta 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 e 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 não tem o que você precisa, mas std :: stringstream faz. Use um stringstream para criar a string e depois extraia a string. Aqui está uma lista abrangente sobre as coisas que você pode fazer. Por exemplo:

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

lhe dará 10 casas decimais de precisão ao imprimir um duplo ou float.

Você poderia tentar isso:

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

Testado, resposta de qualidade de produção

 #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 é o código que eu uso para fazer isso no meu programa … Não é nada extravagante, mas faz o truque … Note, você terá que ajustar o seu tamanho, conforme aplicável. MAX_BUFFER para mim é 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; } 

Tirou a ideia da resposta de Dacav e pixelpoint . Eu brinquei um pouco e entendi:

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

Com a prática de programação sã, acredito que o código deve ser suficiente, mas ainda estou aberto a alternativas mais seguras que ainda são bastante simples e não exigiriam o C ++ 11.


E aqui está outra versão que faz uso de um buffer inicial para evitar a segunda chamada para vsnprintf() quando o buffer inicial já é 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); } 

(Acontece que esta versão é apenas semelhante à resposta de Piti Ongmongkolkul , apenas que não usa new e delete[] , e também especifica um tamanho ao criar std::string .

A idéia aqui de não usar new e delete[] é implicar o uso da pilha sobre o heap, já que ele não precisa chamar funções de alocação e desalocação, entretanto, se não for usado adequadamente, pode ser perigoso estourar overflows em alguns ( talvez antigos, ou talvez apenas vulneráveis). Se isso for uma preocupação, sugiro usar new e delete[] . Observe que a única preocupação aqui é com as alocações, já que o vsnprintf() já é chamado com limites, portanto, especificar um limite com base no tamanho alocado no segundo buffer também os impediria.

Eu costumo usar isso:

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

Desvantagem: nem todos os sistemas suportam 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"; } 

Saída:

 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; 

Saída:

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