Apakah ada cara untuk mencapai kelebihan fungsi di C? Saya melihat fungsi sederhana menjadi kelebihan beban
foo (int a)
foo (char b)
foo (float c , int d)
Saya pikir tidak ada jalan lurus ke depan; Saya mencari solusi jika ada.
c
overloading
FL4SOF
sumber
sumber
Jawaban:
Ada beberapa kemungkinan:
sumber
Iya!
Sejak pertanyaan ini diajukan, standar C (tidak ada ekstensi) telah secara efektif mendapatkan dukungan untuk kelebihan fungsi (bukan operator), berkat penambahan
_Generic
kata kunci di C11. (didukung dalam GCC sejak versi 4.9)(Overloading tidak benar-benar "built-in" dalam mode yang ditunjukkan dalam pertanyaan, tapi mati-matian mudah untuk mengimplementasikan sesuatu yang berfungsi seperti itu.)
_Generic
adalah operator waktu kompilasi dalam keluarga yang sama dengansizeof
dan_Alignof
. Ini dijelaskan dalam bagian standar 6.5.1.1. Ia menerima dua parameter utama: ekspresi (yang tidak akan dievaluasi saat runtime), dan daftar asosiasi tipe / ekspresi yang terlihat agak sepertiswitch
blok._Generic
dapatkan keseluruhan jenis ekspresi dan kemudian "aktifkan" untuk memilih ekspresi hasil akhir dalam daftar untuk jenisnya:Ekspresi di atas mengevaluasi ke
2
- jenis ekspresi pengendaliint
, jadi ia memilih ekspresi yang terkait denganint
nilainya. Tidak ada yang tersisa saat runtime. (default
Klausa ini opsional: jika Anda membiarkannya dan jenisnya tidak cocok, itu akan menyebabkan kesalahan kompilasi.)Cara ini berguna untuk kelebihan fungsi adalah dapat dimasukkan oleh preprocessor C dan memilih ekspresi hasil berdasarkan pada jenis argumen yang diteruskan ke makro pengontrol. Jadi (contoh dari standar C):
Makro ini menerapkan
cbrt
operasi kelebihan beban , dengan mengirimkan jenis argumen ke makro, memilih fungsi implementasi yang sesuai, dan kemudian meneruskan argumen makro asli ke fungsi tersebut.Jadi untuk menerapkan contoh asli Anda, kami bisa melakukan ini:
Dalam hal ini kita bisa menggunakan
default:
asosiasi untuk kasus ketiga, tetapi itu tidak menunjukkan bagaimana memperluas prinsip ke beberapa argumen. Hasil akhirnya adalah bahwa Anda dapat menggunakanfoo(...)
kode Anda tanpa khawatir (banyak [1]) tentang jenis argumennya.Untuk situasi yang lebih rumit, misalnya fungsi yang kelebihan jumlah argumen yang lebih besar, atau jumlah yang bervariasi, Anda dapat menggunakan makro utilitas untuk secara otomatis menghasilkan struktur pengiriman statis:
( implementasi di sini ) Jadi, dengan sedikit usaha, Anda dapat mengurangi jumlah pelat ketel agar tampak seperti bahasa dengan dukungan asli untuk kelebihan muatan.
Selain itu , sudah dimungkinkan untuk membebani jumlah argumen (bukan tipe) di C99.
[1] perhatikan bahwa cara C mengevaluasi tipe mungkin membuat Anda tersandung. Ini akan memilih
foo_int
jika Anda mencoba memberikan karakter literal, misalnya, dan Anda perlu sedikit mengacaukannya jika Anda ingin overload Anda mendukung string literal. Namun secara keseluruhan masih cukup keren.sumber
Seperti yang telah dinyatakan, kelebihan dalam arti yang Anda maksud tidak didukung oleh C. Ungkapan umum untuk menyelesaikan masalah adalah membuat fungsi menerima gabungan yang ditandai . Ini diimplementasikan oleh
struct
parameter, di manastruct
itu sendiri terdiri dari semacam indikator jenis, sepertienum
, danunion
dari berbagai jenis nilai. Contoh:sumber
whatever
s menjadi fungsi yang terpisah (set_int
,set_float
, dll). Kemudian "penandaan dengan tipe" menjadi "tambahkan nama tipe ke nama fungsi". Versi dalam jawaban ini melibatkan lebih banyak pengetikan, lebih banyak biaya runtime, lebih banyak kemungkinan kesalahan yang tidak akan tertangkap saat kompilasi ... Saya gagal melihat keuntungan sama sekali untuk melakukan hal-hal dengan cara ini! 16 suara positif ?!Berikut adalah contoh paling jelas dan paling ringkas yang saya temukan mendemonstrasikan kelebihan fungsi di C:
https://gist.github.com/barosl/e0af4a92b2b8cabd05a7
sumber
Jika kompiler Anda adalah gcc dan Anda tidak keberatan melakukan pembaruan tangan setiap kali Anda menambahkan kelebihan baru Anda dapat melakukan beberapa keajaiban makro dan mendapatkan hasil yang Anda inginkan dari segi penelepon, tidak baik untuk menulis ... tetapi mungkin saja
lihat __builtin_types_compatible_p, lalu gunakan untuk mendefinisikan makro yang melakukan sesuatu seperti
tapi ya jahat, hanya saja jangan
EDIT: C1X akan mendapatkan dukungan untuk tipe ekspresi generik yang terlihat seperti ini:
sumber
Ya, semacam.
Ini contohnya:
Ini akan menampilkan 0 dan halo .. dari printA dan printB.
sumber
Pendekatan berikut mirip dengan a2800276 , tetapi dengan beberapa makro C99 ditambahkan:
sumber
Ini mungkin tidak membantu sama sekali, tetapi jika Anda menggunakan dentang Anda dapat menggunakan atribut overloadable - Ini berfungsi bahkan ketika dikompilasi sebagai C
http://clang.llvm.org/docs/AttributeReference.html#overloadable
Header
Penerapan
sumber
Dalam arti yang Anda maksud - tidak, Anda tidak bisa.
Anda dapat mendeklarasikan
va_arg
fungsi sepertivoid my_func(char* format, ...);
, tetapi Anda harus memberikan beberapa jenis informasi tentang jumlah variabel dan jenisnya dalam argumen pertama - seperti yang
printf()
dilakukan.sumber
Biasanya kutil untuk menunjukkan jenis ditambahkan atau diawali dengan nama. Anda bisa lolos dengan makro adalah beberapa contoh, tetapi itu tergantung pada apa yang Anda coba lakukan. Tidak ada polimorfisme di C, hanya paksaan.
Operasi generik sederhana dapat dilakukan dengan makro:
Jika kompiler Anda mendukung typeof , operasi yang lebih rumit dapat dimasukkan ke makro. Anda kemudian dapat memiliki simbol foo (x) untuk mendukung jenis operasi yang sama berbeda, tetapi Anda tidak dapat memvariasikan perilaku di antara kelebihan beban yang berbeda. Jika Anda menginginkan fungsi yang sebenarnya daripada makro, Anda mungkin dapat menempelkan tipe ke nama dan menggunakan tempelan kedua untuk mengaksesnya (saya belum mencoba).
sumber
Jawaban Leushenko benar-benar keren - semata-mata:
foo
contohnya tidak dikompilasi dengan GCC, yang gagal padafoo(7)
, tersandungFIRST
makro dan panggilan fungsi yang sebenarnya ((_1, __VA_ARGS__)
, tetap dengan koma surplus. Selain itu, kami dalam masalah jika kami ingin memberikan kelebihan tambahan , sepertifoo(double)
.Jadi saya memutuskan untuk menguraikan jawaban sedikit lebih jauh, termasuk untuk memungkinkan kekosongan yang berlebihan (
foo(void)
- yang menyebabkan beberapa masalah ...).Gagasannya sekarang adalah: Tetapkan lebih dari satu generik dalam makro yang berbeda dan biarkan pilih yang benar sesuai dengan jumlah argumen!
Jumlah argumen cukup mudah, berdasarkan jawaban ini :
Itu bagus, kami memutuskan untuk salah satu
SELECT_1
atauSELECT_2
(atau lebih banyak argumen, jika Anda ingin / membutuhkannya), jadi kami hanya perlu mendefinisikan yang tepat:OK, saya sudah menambahkan void overload - namun, ini sebenarnya tidak tercakup oleh standar C, yang tidak memungkinkan argumen variadik kosong, yaitu kita kemudian bergantung pada ekstensi kompilator !
Pada awalnya, panggilan makro kosong (
foo()
) masih menghasilkan token, tetapi yang kosong. Jadi makro penghitungan sebenarnya mengembalikan 1 bukannya 0 bahkan pada panggilan makro kosong. Kita dapat "dengan mudah" menghilangkan masalah ini, jika kita menempatkan koma setelah__VA_ARGS__
kondisional , tergantung pada daftar yang kosong atau tidak:Itu terlihat mudah, tetapi
COMMA
makronya cukup berat; untungnya, topik ini sudah dibahas di blog Jens Gustedt (terima kasih, Jens). Trik dasarnya adalah fungsi makro tidak diperluas jika tidak diikuti oleh tanda kurung, untuk penjelasan lebih lanjut, lihat blog Jens ... Kita hanya perlu memodifikasi makro sedikit untuk kebutuhan kita (saya akan menggunakan nama yang lebih pendek dan lebih sedikit argumen untuk singkatnya).Dan sekarang kita baik-baik saja ...
Kode lengkap dalam satu blok:
sumber
Tidak bisakah Anda menggunakan C ++ dan tidak menggunakan semua fitur C ++ lainnya kecuali yang ini?
Jika masih ada C ketat saja maka saya akan merekomendasikan fungsi variadic sebagai gantinya.
sumber
Cobalah untuk mendeklarasikan fungsi-fungsi ini seolah-
extern "C++"
olah kompiler Anda mendukung ini, http://msdn.microsoft.com/en-us/library/s6y4zxec(VS.80).aspxsumber
Saya harap kode di bawah ini akan membantu Anda untuk memahami kelebihan fungsi
sumber