C ++ modern membuat ini sangat sederhana.
C ++ 20
C ++ 20 memperkenalkan std::format, yang memungkinkan Anda untuk melakukan hal itu. Ini menggunakan bidang pengganti yang mirip dengan yang ada di python :
#include <iostream>
#include <format>
int main() {
std::cout << std::format("Hello {}!\n", "world");
}
Lihat dokumentasi lengkapnya ! Ini merupakan peningkatan kualitas hidup yang luar biasa.
C ++ 11
Dengan C ++ 11 s std::snprintf, ini sudah menjadi tugas yang cukup mudah dan aman.
#include <memory>
#include <string>
#include <stdexcept>
template<typename ... Args>
std::string string_format( const std::string& format, Args ... args )
{
size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1; // Extra space for '\0'
if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
std::unique_ptr<char[]> buf( new char[ size ] );
snprintf( buf.get(), size, format.c_str(), args ... );
return std::string( buf.get(), buf.get() + size - 1 ); // We don't want the '\0' inside
}
Cuplikan kode di atas dilisensikan di bawah CC0 1.0 .
Penjelasan baris demi baris:
Tujuan: Menulis ke achar*dengan menggunakan std::snprintflalu mengonversinya menjadi astd::string.
Pertama, kami menentukan panjang array char yang diinginkan menggunakan kondisi khusus di snprintf. Dari cppreference.com :
Nilai pengembalian
[...] Jika string yang dihasilkan terpotong karena batas buf_size, fungsi mengembalikan jumlah karakter (tidak termasuk terminasi null-byte) yang seharusnya ditulis, jika batas itu tidak dikenakan.
Ini berarti bahwa ukuran yang diinginkan adalah jumlah karakter ditambah satu , sehingga null-terminator akan duduk setelah semua karakter lain dan dapat dipotong oleh konstruktor string lagi. Masalah ini dijelaskan oleh @ alexk7 di komentar.
size_t size = snprintf( nullptr, 0, format.c_str(), args ... ) + 1;
snprintfakan mengembalikan angka negatif jika terjadi kesalahan, jadi kami kemudian memeriksa apakah pemformatan berfungsi sesuai keinginan. Tidak melakukan ini dapat menyebabkan kesalahan diam atau alokasi buffer besar, seperti yang ditunjukkan oleh @ead di komentar.
if( size <= 0 ){ throw std::runtime_error( "Error during formatting." ); }
Selanjutnya, kami mengalokasikan array karakter baru dan menetapkannya ke a std::unique_ptr. Ini umumnya disarankan, karena Anda tidak perlu melakukannya deletelagi secara manual .
Perhatikan bahwa ini bukan cara yang aman untuk mengalokasikan unique_ptrtipe yang ditentukan pengguna karena Anda tidak dapat membatalkan alokasi memori jika konstruktor melempar pengecualian!
std::unique_ptr<char[]> buf( new char[ size ] );
Setelah itu, kita tentu saja bisa menggunakan snprintfuntuk tujuan penggunaannya dan menulis string yang diformat ke char[].
snprintf( buf.get(), size, format.c_str(), args ... );
Akhirnya, kami membuat dan mengembalikan yang baru std::stringdari itu, memastikan untuk menghilangkan null-terminator di akhir.
return std::string( buf.get(), buf.get() + size - 1 );
Anda dapat melihat contoh beraksi di sini .
Jika Anda juga ingin menggunakan std::stringdalam daftar argumen, lihat intisari ini .
Informasi tambahan untuk pengguna Visual Studio :
Sebagaimana dijelaskan dalam jawaban ini , Microsoft berganti nama std::snprintfmenjadi _snprintf(ya, tanpa std::). MS selanjutnya menetapkannya sebagai usang dan menyarankan untuk menggunakannya _snprintf_ssebagai gantinya, namun _snprintf_stidak akan menerima buffer menjadi nol atau lebih kecil dari output yang diformat dan tidak akan menghitung panjang output jika itu terjadi. Jadi untuk menghilangkan peringatan penghentian selama kompilasi, Anda dapat memasukkan baris berikut di bagian atas file yang berisi penggunaan _snprintf:
#pragma warning(disable : 4996)
Pikiran terakhir
Banyak jawaban untuk pertanyaan ini ditulis sebelum waktu C ++ 11 dan menggunakan panjang buffer tetap atau vargs. Kecuali Anda terjebak dengan versi lama C ++, saya tidak akan merekomendasikan menggunakan solusi tersebut. Idealnya, gunakan cara C ++ 20.
Karena solusi C ++ 11 dalam jawaban ini menggunakan templat, ini dapat menghasilkan sedikit kode jika banyak digunakan. Namun, kecuali Anda mengembangkan untuk lingkungan dengan ruang biner yang sangat terbatas, ini tidak akan menjadi masalah dan masih merupakan peningkatan besar atas solusi lain dalam kejelasan dan keamanan.
Jika efisiensi ruang sangat penting, dua solusi dengan vargs dan vsnprintf ini dapat bermanfaat.
JANGAN GUNAKAN solusi apa pun dengan panjang buffer tetap, yang hanya meminta masalah.
boost::format(seperti solusi kennytm gunakan di sini ).boost::formatsudah mendukung operator stream C ++ juga! Contoh:cout << format("helloworld. a=%s, b=%s, c=%s") % 123 % 123.123 % "this is a test" << endl;.boost::formatmemiliki paling sedikit baris kode ... ditinjau oleh rekan dan terintegrasi dengan baik dengan aliran C ++.