Deklarator fungsi C
Pertama-tama, ada C. Dalam C, A a()
adalah deklarasi fungsi. Misalnya, putchar
memiliki deklarasi berikut. Biasanya, deklarasi semacam itu disimpan dalam file header, namun tidak ada yang menghentikan Anda dari menulisnya secara manual, jika Anda tahu bagaimana deklarasi fungsi itu terlihat. Nama argumen adalah opsional dalam deklarasi, jadi saya menghilangkannya dalam contoh ini.
int putchar(int);
Ini memungkinkan Anda untuk menulis kode seperti ini.
int puts(const char *);
int main() {
puts("Hello, world!");
}
C juga memungkinkan Anda untuk mendefinisikan fungsi yang mengambil fungsi sebagai argumen, dengan sintaks yang dapat dibaca yang terlihat seperti panggilan fungsi (well, ini dapat dibaca, selama Anda tidak akan mengembalikan pointer ke fungsi).
#include <stdio.h>
int eighty_four() {
return 84;
}
int output_result(int callback()) {
printf("Returned: %d\n", callback());
return 0;
}
int main() {
return output_result(eighty_four);
}
Seperti yang saya sebutkan, C memungkinkan menghilangkan nama argumen dalam file header, oleh karena itu output_result
akan terlihat seperti ini di file header.
int output_result(int());
Satu argumen dalam konstruktor
Apakah kamu tidak mengenali yang itu? Baiklah, izinkan saya mengingatkan Anda.
A a(B());
Yap, itu deklarasi fungsi yang persis sama. A
adalah int
, a
adalah output_result
, dan B
sedang int
.
Anda dapat dengan mudah melihat konflik C dengan fitur baru C ++. Tepatnya, konstruktor menjadi nama kelas dan tanda kurung, dan sintaks deklarasi alternatif dengan ()
alih - alih =
. Secara desain, C ++ mencoba untuk kompatibel dengan kode C, dan karena itu harus berurusan dengan kasus ini - bahkan jika praktis tidak ada yang peduli. Oleh karena itu, fitur C lama memiliki prioritas di atas fitur C ++ baru. Tata bahasa deklarasi mencoba mencocokkan nama sebagai fungsi, sebelum kembali ke sintaks baru dengan()
jika gagal.
Jika salah satu fitur tersebut tidak ada, atau memiliki sintaks yang berbeda (seperti {}
dalam C ++ 11), masalah ini tidak akan pernah terjadi untuk sintaksis dengan satu argumen.
Sekarang Anda mungkin bertanya mengapa itu A a((B()))
berhasil. Baiklah, mari kita nyatakan output_result
dengan tanda kurung yang tidak berguna.
int output_result((int()));
Itu tidak akan berhasil. Tata bahasanya membutuhkan variabel untuk tidak berada dalam tanda kurung.
<stdin>:1:19: error: expected declaration specifiers or ‘...’ before ‘(’ token
Namun, C ++ mengharapkan ekspresi standar di sini. Di C ++, Anda dapat menulis kode berikut.
int value = int();
Dan kode berikut.
int value = ((((int()))));
C ++ mengharapkan ekspresi di dalam tanda kurung di dalam menjadi ... well ... ekspresi, sebagai lawan dari tipe C mengharapkan. Kurung tidak ada artinya di sini. Namun, dengan menyisipkan tanda kurung yang tidak berguna, deklarasi fungsi C tidak cocok, dan sintaks baru dapat dicocokkan dengan benar (yang hanya mengharapkan ekspresi, seperti 2 + 2
).
Lebih banyak argumen dalam konstruktor
Tentunya satu argumen itu bagus, tapi bagaimana dengan dua? Bukan karena konstruktor mungkin hanya memiliki satu argumen. Salah satu kelas bawaan yang mengambil dua argumen adalahstd::string
std::string hundred_dots(100, '.');
Ini semua baik dan baik-baik saja (secara teknis, itu akan sangat mengurai jika dituliskan std::string wat(int(), char())
, tetapi mari kita jujur - siapa yang akan menulis itu? Tapi mari kita asumsikan kode ini memiliki masalah yang menjengkelkan. Anda akan menganggap bahwa Anda harus meletakkan semuanya dalam tanda kurung.
std::string hundred_dots((100, '.'));
Tidak juga.
<stdin>:2:36: error: invalid conversion from ‘char’ to ‘const char*’ [-fpermissive]
In file included from /usr/include/c++/4.8/string:53:0,
from <stdin>:1:
/usr/include/c++/4.8/bits/basic_string.tcc:212:5: error: initializing argument 1 of ‘std::basic_string<_CharT, _Traits, _Alloc>::basic_string(const _CharT*, const _Alloc&) [with _CharT = char; _Traits = std::char_traits<char>; _Alloc = std::allocator<char>]’ [-fpermissive]
basic_string<_CharT, _Traits, _Alloc>::
^
Saya tidak yakin mengapa g ++ mencoba untuk mengkonversi char
ke const char *
. Either way, konstruktor dipanggil hanya dengan satu nilai tipe char
. Tidak ada overload yang memiliki satu argumen tipe char
, oleh karena itu kompiler bingung. Anda mungkin bertanya - mengapa argumennya bertipe char?
(100, '.')
Iya, ,
ini operator koma. Operator koma mengambil dua argumen, dan memberikan argumen sisi kanan. Itu tidak benar-benar berguna, tetapi itu sesuatu yang harus diketahui untuk penjelasan saya.
Sebagai gantinya, untuk memecahkan parse yang paling menjengkelkan, kode berikut ini diperlukan.
std::string hundred_dots((100), ('.'));
Argumennya dalam tanda kurung, bukan seluruh ekspresi. Faktanya, hanya satu ekspresi yang perlu di dalam tanda kurung, karena cukup untuk sedikit keluar dari tata bahasa C untuk menggunakan fitur C ++. Hal-hal membawa kita ke titik nol argumen.
Tidak ada argumen dalam konstruktor
Anda mungkin telah memperhatikan eighty_four
fungsi dalam penjelasan saya.
int eighty_four();
Ya, ini juga dipengaruhi oleh parse yang paling menjengkelkan. Ini adalah definisi yang valid, dan kemungkinan besar Anda telah melihat jika Anda membuat file header (dan Anda harus). Menambahkan tanda kurung tidak memperbaikinya.
int eighty_four(());
Kenapa begitu? Ya, ()
itu bukan ekspresi. Di C ++, Anda harus meletakkan ekspresi di antara tanda kurung. Anda tidak dapat menulis auto value = ()
dalam C ++, karena ()
tidak berarti apa-apa (dan bahkan jika itu, seperti tuple kosong (lihat Python), itu akan menjadi satu argumen, bukan nol). Secara praktis itu berarti Anda tidak dapat menggunakan sintaks steno tanpa menggunakan sintaks C ++ 11 {}
, karena tidak ada ekspresi untuk dimasukkan dalam tanda kurung, dan tata bahasa C untuk deklarasi fungsi akan selalu berlaku.
(B())
hanyalah ekspresi C ++, tidak lebih. Ini bukan pengecualian. Satu-satunya perbedaan yang dibuatnya adalah bahwa tidak mungkin itu dapat diuraikan sebagai tipe, dan karenanya tidak.