Saya mencoba menemukan cara yang nyaman untuk menginisialisasi 'pod' struct C ++. Sekarang, pertimbangkan struct berikut:
struct FooBar {
int foo;
float bar;
};
// just to make all examples work in C and C++:
typedef struct FooBar FooBar;
Jika saya ingin menginisialisasi ini dengan mudah di C (!), Saya cukup menulis:
/* A */ FooBar fb = { .foo = 12, .bar = 3.4 }; // illegal C++, legal C
Perhatikan bahwa saya ingin secara eksplisit menghindari notasi berikut, karena menurut saya dibuat untuk mematahkan leher saya jika saya mengubah sesuatu di struct di masa depan:
/* B */ FooBar fb = { 12, 3.4 }; // legal C++, legal C, bad style?
Untuk mencapai yang sama (atau paling tidak serupa) di C ++ seperti pada /* A */
contoh, saya harus mengimplementasikan konstruktor idiot:
FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar) {}
// ->
/* C */ FooBar fb(12, 3.4);
Mana yang baik untuk air mendidih, tetapi tidak cocok untuk orang malas (kemalasan adalah hal yang baik, bukan?). Juga, ini sama buruknya dengan /* B */
contoh, karena tidak secara eksplisit menyatakan nilai yang masuk ke anggota mana.
Jadi, pertanyaan saya pada dasarnya adalah bagaimana saya bisa mencapai sesuatu yang mirip /* A */
atau lebih baik di C ++? Atau, saya akan baik-baik saja dengan penjelasan mengapa saya tidak ingin melakukan ini (yaitu mengapa paradigma mental saya buruk).
EDIT
Dengan nyaman , maksud saya juga dapat dipertahankan dan tidak berlebihan .
sumber
Jawaban:
Inisialisasi yang ditunjuk akan didukung dalam c ++ 2a, tetapi Anda tidak harus menunggu, karena mereka secara resmi didukung oleh GCC, Dentang dan MSVC.
GCC Demo MSVC Demo
sumber
Karena
style A
tidak diizinkan dalam C ++ dan Anda tidak inginstyle B
lalu bagaimana menggunakanstyle BX
:Setidaknya membantu sedikit banyak.
sumber
foo
danbar
di masa mendatang. C masih akan menginisialisasi bidang yang kita inginkan, tetapi C ++ tidak. Dan ini adalah inti dari pertanyaan - bagaimana mencapai hasil yang sama dalam C ++. Maksudku, Python melakukan ini dengan argumen bernama, C - dengan bidang "bernama", dan C ++ harus memiliki sesuatu juga, saya harap.explicit FooBar::FooBar(int foo, float bar) : foo(foo), bar(bar)
. Perhatikan kata kunci eksplisit . Bahkan melanggar standar lebih baik dalam hal keamanan. Dalam Dentang: -Wno-c99-extensionsAnda bisa menggunakan lambda:
Informasi lebih lanjut tentang idiom ini dapat ditemukan di blog Herb Sutter .
sumber
fb.XXX = YYY
.Ekstrak kontants menjadi fungsi yang menggambarkannya (refactoring dasar):
Saya tahu bahwa gaya sangat dekat dengan gaya yang tidak ingin Anda gunakan, tetapi memungkinkan penggantian nilai konstan yang lebih mudah dan juga menjelaskannya (sehingga tidak perlu mengedit komentar), jika mereka pernah mengubahnya.
Hal lain yang dapat Anda lakukan (karena Anda malas) adalah membuat konstruktor sebaris, sehingga Anda tidak perlu mengetik sebanyak (menghapus "Foobar ::" dan menghabiskan waktu beralih antara file h dan cpp):
sumber
Pertanyaan Anda agak sulit karena bahkan fungsinya:
dapat disebut sebagai:
karena aturan promosi dan konversi untuk tipe numerik bawaan. (C tidak pernah diketik dengan sangat kuat)
Di C ++, apa yang Anda inginkan dapat dicapai, meskipun dengan bantuan template dan pernyataan statis:
Di C, Anda dapat memberi nama parameter, tetapi Anda tidak akan pernah lanjut.
Di sisi lain, jika semua yang Anda inginkan bernama parameter, maka Anda menulis banyak kode rumit:
Dan Anda dapat menambahkan perlindungan promosi tipe jika Anda suka.
sumber
Banyak frontend C ++ kompiler (termasuk GCC dan dentang) memahami sintaks initializer C. Jika Anda bisa, cukup gunakan metode itu.
sumber
private: FooBar(float x, int y) {};
Namun cara lain dalam C ++ adalah
sumber
inline
!Opsi D:
FooBar FooBarMake(int foo, float bar)
Legal C, legal C ++. Mudah dioptimalkan untuk POD. Tentu saja tidak ada argumen bernama, tetapi ini seperti semua C ++. Jika Anda ingin argumen bernama, Objective C harus menjadi pilihan yang lebih baik.
Opsi E:
Legal C, legal C ++. Argumen yang dinamai.
sumber
FooBar fb = {};
di C ++, ini secara default menginisialisasi semua anggota struct.Saya tahu pertanyaan ini sudah lama, tetapi ada cara untuk menyelesaikan ini sampai C ++ 20 akhirnya membawa fitur ini dari C ke C ++. Apa yang dapat Anda lakukan untuk menyelesaikan ini adalah menggunakan macro preprocessor dengan static_asserts untuk memeriksa inisialisasi Anda valid. (Saya tahu makro umumnya buruk, tetapi di sini saya tidak melihat cara lain.) Lihat contoh kode di bawah ini:
Kemudian ketika Anda memiliki struct dengan atribut const, Anda bisa melakukan ini:
Agak merepotkan, karena Anda memerlukan makro untuk setiap kemungkinan jumlah atribut dan Anda perlu mengulangi jenis dan nama instance Anda dalam panggilan makro. Anda juga tidak dapat menggunakan makro dalam pernyataan pengembalian, karena pernyataan muncul setelah inisialisasi.
Tetapi itu memecahkan masalah Anda: Ketika Anda mengubah struct, panggilan akan gagal pada waktu kompilasi.
Jika Anda menggunakan C ++ 17, Anda bahkan dapat membuat makro ini lebih ketat dengan memaksa jenis yang sama, misalnya:
sumber
Jalan
/* B */
ini baik-baik saja di C ++ juga C ++ 0x akan memperpanjang sintaks sehingga berguna untuk wadah C ++ juga. Saya tidak mengerti mengapa Anda menyebutnya gaya buruk?Jika Anda ingin menunjukkan parameter dengan nama maka Anda dapat menggunakan pustaka parameter boost , tetapi itu mungkin membingungkan seseorang yang tidak terbiasa dengannya.
Menyusun ulang anggota struct seperti mengatur ulang parameter fungsi, refactoring seperti itu dapat menyebabkan masalah jika Anda tidak melakukannya dengan sangat hati-hati.
sumber
Bagaimana dengan sintaks ini?
Baru saja diuji pada Microsoft Visual C ++ 2015 dan pada g ++ 6.0.2. Bekerja dengan baik.
Anda dapat membuat makro spesifik juga jika Anda ingin menghindari duplikasi nama variabel.
sumber
clang++
3.5.0-10 dengan-Weverything -std=c++1z
sepertinya mengkonfirmasi itu. Tapi itu tidak beres. Apakah Anda tahu di mana standar menegaskan bahwa ini adalah C ++ yang valid?ABCD abc = { abc.b = 7, abc.a = 5 };
.Bagi saya cara paling malas untuk memungkinkan inzialisasi inline adalah menggunakan makro ini.
Makro itu menciptakan atribut dan metode referensi diri.
sumber