Bagaimana saya bisa menulis fungsi yang menerima sejumlah variabel argumen? Apakah ini mungkin?
c++
variadic-functions
nunos
sumber
sumber
Jawaban:
Anda mungkin tidak boleh, dan Anda mungkin bisa melakukan apa yang ingin Anda lakukan dengan cara yang lebih aman dan sederhana. Secara teknis untuk menggunakan jumlah variabel argumen di C Anda memasukkan stdarg.h. Dari itu Anda akan mendapatkan
va_list
jenis serta tiga fungsi yang beroperasi di dalamnya disebutva_start()
,va_arg()
danva_end()
.Jika Anda bertanya kepada saya, ini berantakan. Terlihat buruk, tidak aman, dan penuh dengan detail teknis yang tidak ada hubungannya dengan apa yang Anda coba capai secara konseptual. Sebagai gantinya, pertimbangkan untuk menggunakan overloading atau inheritance / polymorphism, pola builder (seperti dalam
operator<<()
stream) atau argumen default, dll. Ini semua lebih aman: kompiler mengetahui lebih banyak tentang apa yang Anda coba lakukan sehingga ada lebih banyak kesempatan dapat berhenti Anda sebelum Anda meledakkan kaki Anda.sumber
...
sintaks?printf()
, misalnya, fungsi mem-parsing argumen string untuk token khusus untuk mencari tahu berapa banyak argumen tambahan yang harus diharapkan dalam daftar argumen variabel.<cstdarg>
dalam C ++ bukannya<stdarg.h>
Dalam C ++ 11 Anda memiliki dua opsi baru, seperti halaman referensi fungsi Variadic di bagian Alternatif menyatakan:
Di bawah ini adalah contoh yang menunjukkan kedua alternatif ( lihat langsung ):
Jika Anda menggunakan
gcc
atauclang
kita dapat menggunakan variabel ajaib PRETTY_FUNCTION untuk menampilkan tipe tanda tangan dari fungsi yang dapat membantu dalam memahami apa yang sedang terjadi. Misalnya menggunakan:akan menghasilkan int berikut untuk fungsi variadik dalam contoh ( lihat langsung ):
Di Visual Studio Anda dapat menggunakan FUNCSIG .
Perbarui Pra C ++ 11
Pra C ++ 11 alternatif untuk std :: initializer_list akan menjadi std :: vector atau salah satu wadah standar lainnya :
dan alternatif untuk templat variadic akan menjadi fungsi variadic meskipun mereka bukan tipe-aman dan secara umum rawan kesalahan dan bisa tidak aman untuk digunakan tetapi satu-satunya alternatif potensial lainnya adalah dengan menggunakan argumen default , meskipun itu memiliki penggunaan terbatas. Contoh di bawah ini adalah versi modifikasi dari kode sampel dalam referensi yang ditautkan:
Menggunakan fungsi variadic juga dilengkapi dengan batasan dalam argumen yang dapat Anda berikan yang dirinci dalam konsep C ++ standar di bagian
5.2.2
Function call paragraf 7 :sumber
typename
vs Anda diclass
atas disengaja? Jika demikian, tolong jelaskan.initializer_list
rekursif?Solusi C ++ 17: keamanan tipe penuh + sintaksis panggilan yang bagus
Karena pengenalan templat variadic di C ++ 11 dan lipat ekspresi dalam C ++ 17, dimungkinkan untuk mendefinisikan fungsi templat yang, di situs pemanggil, dapat dipanggil seolah-olah itu adalah fungsi varidic tetapi dengan keuntungan untuk :
Berikut adalah contoh untuk tipe argumen campuran
Dan satu lagi dengan pencocokan jenis yang dipaksakan untuk semua argumen:
Informasi lebih lanjut:
sumber
template<class Head, class... Tail, class = std::enable_if_t<are_same<Head, Tail...>::value, void>>
Head
danTail...
sama ", di mana " sama " berartistd::conjunction<std::is_same<Head, Tail>...>
. Baca definisi terakhir ini sebagai "Head
sama dengan semuaTail...
".di c ++ 11 yang dapat Anda lakukan:
daftar inisialisasi FTW!
sumber
Dalam C ++ 11 ada cara untuk melakukan templat argumen variabel yang mengarah ke cara yang benar-benar elegan dan aman untuk memiliki fungsi argumen variabel. Bjarne sendiri memberikan contoh printf yang bagus menggunakan templat argumen variabel dalam C ++ 11FAQ .
Secara pribadi, saya menganggap ini sangat elegan sehingga saya bahkan tidak akan repot dengan fungsi argumen variabel dalam C ++ sampai kompiler itu memiliki dukungan untuk templat argumen variabel C ++ 11.
sumber
,
operator dengan ekspresi lipatan). Kalau tidak, saya rasa tidak.Fungsi variadik C-style didukung dalam C ++.
Namun, sebagian besar pustaka C ++ menggunakan idiom alternatif misalnya sedangkan
'c' printf
fungsi mengambil argumen variabelc++ cout
objek menggunakan<<
overloading yang membahas keamanan tipe dan ADT (mungkin dengan biaya kesederhanaan implementasi).sumber
std::initializer_lists
... Dan ini sudah memperkenalkan kompleksitas besar pada tugas sederhana.Terlepas dari varargs atau overloading, Anda dapat mempertimbangkan untuk menjumlahkan argumen Anda dalam std :: vector atau wadah lain (std :: map misalnya). Sesuatu seperti ini:
Dengan cara ini Anda akan mendapatkan keamanan jenis dan makna logis dari argumen variadik ini akan terlihat jelas.
Tentunya pendekatan ini dapat memiliki masalah kinerja tetapi Anda tidak perlu khawatir tentang hal itu kecuali Anda yakin bahwa Anda tidak dapat membayar harganya. Ini adalah semacam pendekatan "Pythonic" untuk c ++ ...
sumber
Satu-satunya cara adalah melalui penggunaan argumen variabel gaya C, seperti dijelaskan di sini . Perhatikan bahwa ini bukan praktik yang disarankan, karena ini bukan typesafe dan rawan kesalahan.
sumber
Tidak ada cara C ++ standar untuk melakukan ini tanpa menggunakan varargs C-style (
...
).Tentu saja ada argumen default yang semacam "terlihat" seperti jumlah variabel argumen tergantung pada konteksnya:
Keempat panggilan fungsi panggilan
myfunc
dengan berbagai jumlah argumen. Jika tidak ada yang diberikan, argumen default digunakan. Namun perlu dicatat, bahwa Anda hanya bisa menghilangkan argumen trailing. Tidak ada cara, misalnya untuk menghilangkani
dan memberi sajaj
.sumber
Mungkin Anda ingin parameter kelebihan muatan atau default - tentukan fungsi yang sama dengan parameter bawaan:
Ini akan memungkinkan Anda untuk memanggil metode dengan satu dari empat panggilan berbeda:
... atau Anda bisa mencari konvensi panggilan v_args dari C.
sumber
Jika Anda tahu kisaran jumlah argumen yang akan disediakan, Anda selalu dapat menggunakan beberapa fungsi yang berlebihan, seperti
dan seterusnya...
sumber
Menggunakan templat variadic, contoh untuk mereproduksi
console.log
seperti yang terlihat di JavaScript:Nama file misalnya
js_console.h
:sumber
Seperti orang lain katakan, varargs C-style. Tetapi Anda juga dapat melakukan sesuatu yang mirip dengan argumen default.
sumber
Mungkin sekarang ... menggunakan sembarang dorongan dan templat. Dalam kasus ini, tipe argumen dapat dicampur
sumber
Gabungkan solusi C dan C ++ untuk opsi semantik yang paling sederhana, performan, dan paling dinamis. Jika Anda gagal, coba sesuatu yang lain.
Pengguna menulis:
Secara semantik, ini terlihat dan terasa persis seperti fungsi n-argumen. Di bawah tenda, Anda dapat membukanya satu arah atau yang lain.
sumber
Kita juga bisa menggunakan initializer_list jika semua argumen adalah konst dan dari jenis yang sama
sumber
Versi sederhana
sumber