C ++ 11 memperkenalkan user-defined literal yang akan memungkinkan pengenalan sintaks literal baru berdasarkan literal yang ada ( int
, hex
, string
, float
) sehingga jenis apapun akan dapat memiliki presentasi literal.
Contoh:
// imaginary numbers
std::complex<long double> operator "" _i(long double d) // cooked form
{
return std::complex<long double>(0, d);
}
auto val = 3.14_i; // val = complex<long double>(0, 3.14)
// binary values
int operator "" _B(const char*); // raw form
int answer = 101010_B; // answer = 42
// std::string
std::string operator "" _s(const char* str, size_t /*length*/)
{
return std::string(str);
}
auto hi = "hello"_s + " world"; // + works, "hello"_s is a string not a pointer
// units
assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds
Pada pandangan pertama ini terlihat sangat keren tapi saya bertanya-tanya bagaimana ini benar-benar berlaku, ketika saya mencoba berpikir untuk memiliki sufiks _AD
dan _BC
membuat tanggal saya menemukan itu bermasalah karena pesanan operator. 1974/01/06_AD
pertama akan mengevaluasi 1974/01
(sebagai int
s polos ) dan hanya kemudian 06_AD
(untuk mengatakan apa-apa Agustus dan September harus ditulis tanpa 0
alasan oktal). Ini dapat diatasi dengan membuat sintaks 1974-1/6_AD
agar urutan evaluasi operator berfungsi tetapi kikuk.
Jadi yang menjadi pertanyaan saya adalah ini, apakah Anda merasa fitur ini akan membenarkan dirinya sendiri? Apa literal lain yang ingin Anda definisikan yang akan membuat kode C ++ Anda lebih mudah dibaca?
Sintaks yang diperbarui agar sesuai dengan konsep akhir pada Juni 2011
sumber
string operator "" _s(const char*s);"
tidak dapat digunakan untuk menguraikan"hello"_s"
. Ini adalah string literal dan akan mencari operator dengansize_t
parameter tambahan . Apakah saya benar?uint16_t
yang perilakunya bergantung pada implementasi, dengan tipe yang serupauwrap16
danunum16
yang perilakunya bebas implementasi, seperti yang diberikanuwrap16 w=1; unum16 n=1;
ekspresiw-2
dann-2
akan menghasilkan(uwrap16)65535
dan(int)-1
, masing-masing [uint16_t
akan menghasilkan hasil pertama pada sistem di manaint
16 bit, dan yang kedua pada sistem di manaint
lebih besar]. Masalah terbesar yang saya lihat adalah menangani literal angka.sizeof
mengembalikan tipe integer yang bergantung pada implementasi, tetapi situasi masih dapat dibuat jauh lebih baik daripada sebelumnya. Apa yang akan Anda pikirkan tentang konsep itu?Jawaban:
Inilah kasus di mana ada keuntungan menggunakan literal yang ditentukan pengguna alih-alih panggilan konstruktor:
Keuntungannya adalah pengecualian run-time dikonversi menjadi kesalahan waktu kompilasi. Anda tidak bisa menambahkan pernyataan statis ke bitet ctor yang mengambil string (setidaknya bukan tanpa argumen templat string).
sumber
Pada pandangan pertama, tampaknya itu adalah gula sintaksis sederhana.
Tetapi ketika melihat lebih dalam, kita melihat itu lebih dari gula sintaksis, karena memperluas opsi pengguna C ++ untuk membuat tipe yang ditentukan pengguna yang berperilaku persis seperti tipe bawaan yang berbeda. Dalam hal ini, "bonus" kecil ini adalah tambahan C ++ 11 yang sangat menarik untuk C ++.
Apakah kita benar-benar membutuhkannya di C ++?
Saya melihat beberapa kegunaan dalam kode yang saya tulis dalam beberapa tahun terakhir, tetapi hanya karena saya tidak menggunakannya dalam C ++ tidak berarti itu tidak menarik untuk pengembang C ++ lainnya .
Kami telah menggunakan dalam C ++ (dan dalam C, saya kira), literal yang ditentukan compiler, untuk mengetikkan bilangan bulat sebagai bilangan bulat pendek atau panjang, bilangan real sebagai float atau double (atau bahkan double panjang), dan string karakter sebagai karakter normal atau lebar karakter .
Di C ++, kami memiliki kemungkinan untuk membuat tipe kami sendiri (yaitu kelas), dengan kemungkinan tidak ada overhead (inlining, dll.). Kami memiliki kemungkinan untuk menambahkan operator ke tipenya, agar mereka berperilaku seperti tipe bawaan yang serupa, yang memungkinkan pengembang C ++ untuk menggunakan matriks dan bilangan kompleks secara alami seperti yang akan mereka miliki jika ini telah ditambahkan ke bahasa itu sendiri. Kami bahkan dapat menambahkan operator cor (yang biasanya merupakan ide yang buruk, tetapi kadang-kadang, itu adalah solusi yang tepat).
Kami masih melewatkan satu hal untuk berperilaku tipe pengguna sebagai tipe bawaan: literal yang ditentukan pengguna.
Jadi, saya kira itu adalah evolusi alami untuk bahasa, tetapi untuk selengkap mungkin: " Jika Anda ingin membuat suatu jenis, dan Anda ingin agar berperilaku sebanyak mungkin sebagai jenis bawaan, berikut adalah alat-alatnya. .. "
Saya kira itu sangat mirip dengan keputusan .NET untuk membuat setiap primitif sebuah struct, termasuk boolean, integer, dll., Dan memiliki semua struct berasal dari Object. Keputusan ini sendiri menempatkan .NET jauh di luar jangkauan Java ketika bekerja dengan primitif, tidak peduli berapa banyak hacking tinju / unboxing yang akan ditambahkan Java ke spesifikasinya.
Apakah ANDA benar-benar membutuhkannya di C ++?
Pertanyaan ini untuk ANDA jawab. Bukan Bjarne Stroustrup. Bukan Herb Sutter. Bukan apa pun anggota komite standar C ++. Inilah sebabnya mengapa Anda memiliki pilihan dalam C ++ , dan mereka tidak akan membatasi notasi yang berguna untuk tipe bawaan saja.
Jika Anda membutuhkannya, maka itu adalah tambahan selamat datang. Jika Anda tidak, baik ... Jangan menggunakannya. Anda tidak akan dikenakan biaya.
Selamat datang di C ++, bahasa tempat fitur opsional.
Bengkak??? Tunjukkan kompleksmu !!!
Ada perbedaan antara kembung dan kompleks (pun intended).
Seperti yang ditunjukkan oleh Niels di Apa kemampuan baru yang ditambahkan oleh literal yang ditetapkan pengguna ke C ++? , bisa menulis bilangan kompleks adalah salah satu dari dua fitur yang ditambahkan "baru-baru ini" ke C dan C ++:
Sekarang, tipe C99 "komplek ganda" dan tipe C ++ "std :: complex" dapat dikalikan, ditambahkan, kurangi, dll., Menggunakan operator yang berlebihan.
Namun di C99, mereka hanya menambahkan tipe lain sebagai tipe bawaan, dan dukungan operator berlebih bawaan. Dan mereka menambahkan fitur literal bawaan lainnya.
Dalam C ++, mereka hanya menggunakan fitur bahasa yang ada, melihat bahwa fitur literal adalah evolusi alami dari bahasa, dan dengan demikian menambahkannya.
Di C, jika Anda memerlukan peningkatan notasi yang sama untuk tipe lain, Anda kurang beruntung sampai lobi Anda menambahkan fungsi gelombang kuantum (atau titik 3D, atau tipe dasar apa pun yang Anda gunakan di bidang pekerjaan) ke Standar C sebagai tipe bawaan berhasil.
Di C ++ 11, Anda bisa melakukannya sendiri:
Apakah kembung? Tidak , perlu ada di sana, seperti yang ditunjukkan oleh bagaimana kedua kompleks C dan C ++ membutuhkan cara untuk mewakili nilai kompleks literal mereka.
Apakah desainnya salah? Tidak , ini dirancang seperti setiap fitur C ++ lainnya, dengan ekstensibilitas dalam pikiran.
Apakah hanya untuk keperluan notasi? Tidak , karena bahkan dapat menambahkan keamanan jenis ke kode Anda.
Misalnya, mari kita bayangkan kode berorientasi CSS:
Maka sangat mudah untuk menerapkan pengetikan yang kuat untuk penugasan nilai.
Apakah ini berbahaya?
Pertanyaan bagus. Bisakah fungsi-fungsi ini di-namespace? Jika ya, maka Jackpot!
Bagaimanapun, seperti semua hal lainnya, Anda dapat bunuh diri jika alat digunakan secara tidak benar . C sangat kuat, dan Anda bisa menembak kepala Anda jika Anda menyalahgunakan senjata C. C ++ memiliki senjata C, tetapi juga pisau bedah, taser, dan alat apa pun lainnya yang akan Anda temukan di toolkit. Anda bisa menyalahgunakan pisau bedah dan membuat darah Anda mati sendiri. Atau Anda dapat membuat kode yang sangat elegan dan kuat.
Jadi, seperti setiap fitur C ++, apakah Anda benar-benar membutuhkannya? Ini adalah pertanyaan yang harus Anda jawab sebelum menggunakannya dalam C ++. Jika tidak, Anda tidak perlu membayar apa-apa. Tetapi jika Anda benar-benar membutuhkannya, setidaknya, bahasa tersebut tidak akan mengecewakan Anda.
Contoh tanggal?
Kesalahan Anda, menurut saya, adalah Anda menggabungkan operator:
Ini tidak dapat dihindari, karena / sebagai operator, kompiler harus mengartikannya. Dan, AFAIK, itu hal yang baik.
Untuk menemukan solusi untuk masalah Anda, saya akan menulis literal dengan beberapa cara lain. Sebagai contoh:
Secara pribadi, saya akan memilih integer dan tanggal ISO, tetapi itu tergantung pada kebutuhan ANDA. Yang merupakan inti dari membiarkan pengguna menentukan nama literalnya sendiri.
sumber
you can write 1+2i, but you still can't write a+bi, so there's absolutely no point
Bahkan mengabaikana+bi
contoh Anda adalah konyol, fakta bahwa Anda menganggapnya sebagai "frekuensi rendah" tidak berarti semua orang melakukannya. . . Melihat gambar besar, intinya adalah untuk memastikan objek yang didefinisikan pengguna dapat sebanyak mungkin dianggap warga kelas bahasa, seperti halnya tipe bawaan. Jadi, jika Anda bisa menulis1.5f
dan1000UL
, mengapa Anda tidak bisa menulis25i
atau bahkan100101b
? Berlawanan dengan C dan Java, tipe pengguna tidak dianggap sebagai warga negara kelas dua bahasa di C ++.Most of data still comes from IO
Ada banyak nilai yang dikodekan dalam kode. Lihatlah semua boolean, semua bilangan bulat, semua ganda yang ada dalam kode, karena lebih mudah untuk menulisx = 2 * y ;
daripada dix = Two * y
mana konstanta yang diketikTwo
dengan kuat . Literal yang didefinisikan pengguna memungkinkan kami untuk mengetikkannya, dan menulis:x = 2_speed * y ;
dan meminta kompiler memverifikasi bahwa perhitungan masuk akal. . . Itu semua tentang pengetikan yang kuat. . . Mungkin Anda tidak akan menggunakannya. Tapi saya yakin akan, segera setelah saya dapat menggunakan kompiler yang diaktifkan C ++ 11 di tempat kerja.Ini sangat bagus untuk kode matematika. Dari pikiran saya, saya dapat melihat penggunaan untuk operator berikut:
deg untuk derajat. Itu membuat penulisan sudut absolut jauh lebih intuitif.
Ini juga dapat digunakan untuk berbagai representasi titik tetap (yang masih digunakan di bidang DSP dan grafik).
Ini terlihat seperti contoh yang bagus bagaimana menggunakannya. Mereka membantu membuat konstanta dalam kode lebih mudah dibaca. Ini adalah alat lain untuk membuat kode tidak dapat dibaca juga, tetapi kami sudah memiliki begitu banyak penyalahgunaan alat yang satu lagi tidak banyak merugikan.
sumber
UDL diberi spasi nama (dan dapat diimpor dengan menggunakan deklarasi / arahan, tetapi Anda tidak dapat secara eksplisit menyebutkan spasi seperti literal
3.14std::i
), yang berarti ada (semoga) tidak akan ada satu ton bentrokan.Fakta bahwa mereka dapat benar-benar templated (dan constexpr'd) berarti Anda dapat melakukan beberapa hal yang cukup kuat dengan UDL. Penulis Bigint akan sangat senang, karena mereka akhirnya dapat memiliki konstanta besar yang sewenang-wenang, dihitung pada waktu kompilasi (melalui constexpr atau templat).
Saya hanya sedih bahwa kita tidak akan melihat beberapa literal yang berguna dalam standar (dari tampilannya), seperti
s
untukstd::string
dani
untuk unit imajiner.Jumlah waktu pengkodean yang akan disimpan oleh UDL sebenarnya tidak terlalu tinggi, tetapi keterbacaan akan sangat meningkat dan semakin banyak perhitungan dapat digeser ke waktu kompilasi untuk eksekusi yang lebih cepat.
sumber
Izinkan saya menambahkan sedikit konteks. Untuk pekerjaan kami, literal yang ditentukan pengguna sangat dibutuhkan. Kami bekerja pada MDE (Model-Driven Engineering). Kami ingin mendefinisikan model dan metamodel dalam C ++. Kami sebenarnya menerapkan pemetaan dari Ecore ke C ++ ( EMF4CPP ).
Masalahnya muncul ketika mampu mendefinisikan elemen model sebagai kelas di C ++. Kami mengambil pendekatan untuk mengubah metamodel (Ecore) menjadi templat dengan argumen. Argumen template adalah karakteristik struktural dari tipe dan kelas. Sebagai contoh, kelas dengan dua atribut int akan menjadi sesuatu seperti:
Namun, ternyata setiap elemen dalam suatu model atau metamodel, biasanya memiliki nama. Kami ingin menulis:
TETAPI, C ++, atau C ++ 0x tidak mengizinkan ini, karena string dilarang sebagai argumen untuk templat. Anda dapat menulis nama char oleh char, tetapi ini diakui berantakan. Dengan literal yang ditentukan oleh pengguna, kita dapat menulis sesuatu yang serupa. Katakanlah kita menggunakan "_n" untuk mengidentifikasi nama elemen model (saya tidak menggunakan sintaks yang tepat, hanya untuk membuat ide):
Akhirnya, memiliki definisi tersebut sebagai templat membantu kita banyak untuk merancang algoritma untuk melintasi elemen model, transformasi model, dll. Yang benar-benar efisien, karena informasi jenis, identifikasi, transformasi, dll. Ditentukan oleh kompiler pada waktu kompilasi.
sumber
by the compiler at compile time
bagian ... :-)Bjarne Stroustrup berbicara tentang UDL dalam pembicaraan C ++ 11 ini , pada bagian pertama tentang antarmuka yang kaya tipe, sekitar 20 menit.
Argumen dasarnya untuk UDL mengambil bentuk silogisme:
Tipe "Trivial", yaitu tipe primitif bawaan, hanya dapat menangkap kesalahan tipe sepele. Antarmuka dengan tipe yang lebih kaya memungkinkan sistem tipe untuk menangkap lebih banyak jenis kesalahan.
Jenis kesalahan jenis yang dapat ditangkap oleh kode yang diketik dengan kaya berdampak pada kode nyata. (Dia memberi contoh Mars Climate Orbiter, yang terkenal gagal karena kesalahan dimensi dalam konstanta penting).
Dalam kode nyata, unit jarang digunakan. Orang tidak menggunakannya, karena menimbulkan runtime compute atau memori overhead untuk membuat tipe kaya terlalu mahal, dan menggunakan kode unit templat C ++ yang sudah ada sebelumnya sangat jelek sehingga tidak ada yang menggunakannya. (Secara empiris, tidak ada yang menggunakannya, meskipun perpustakaan telah ada selama satu dekade).
Oleh karena itu, untuk membuat insinyur menggunakan unit dalam kode nyata, kami membutuhkan perangkat yang (1) tidak menimbulkan overhead runtime dan (2) tidak dapat diterima secara nasional.
sumber
Mendukung pemeriksaan dimensi waktu kompilasi adalah satu-satunya pembenaran yang diperlukan.
Lihat misalnya PhysUnits-CT-Cpp11 , perpustakaan kecil header C ++ 11, C ++ 14 saja untuk analisis dimensi waktu kompilasi dan manipulasi serta konversi unit / kuantitas. Lebih sederhana daripada Boost . Unit , tidak mendukung literal simbol satuan seperti m, g, s, awalan metrik seperti m, k, M, hanya bergantung pada pustaka C ++ standar, hanya SI, kekuatan dimensi yang tidak terpisahkan.
sumber
Hmm ... Saya belum memikirkan fitur ini. Sampel Anda dipikirkan dengan baik dan tentu saja menarik. C ++ sangat kuat seperti sekarang, tetapi sayangnya sintaks yang digunakan dalam potongan kode yang Anda baca terkadang terlalu rumit. Keterbacaan adalah, jika tidak semua, maka setidaknya banyak. Dan fitur seperti itu akan diarahkan untuk lebih mudah dibaca. Jika saya ambil contoh terakhir Anda
... Saya ingin tahu bagaimana Anda mengekspresikannya hari ini. Anda akan memiliki kelas KG dan LB dan Anda akan membandingkan objek implisit:
Dan itu akan berhasil juga. Dengan tipe yang memiliki nama atau tipe yang lebih panjang yang Anda tidak memiliki harapan memiliki konstruktor yang bagus untuk menulis adapter, mungkin ini merupakan tambahan yang bagus untuk pembuatan dan inisialisasi objek implisit on-the-fly. Di sisi lain, Anda sudah dapat membuat dan menginisialisasi objek menggunakan metode juga.
Tapi saya setuju dengan Nils tentang matematika. Fungsi trigonometri C dan C ++ misalnya membutuhkan input dalam radian. Saya pikir dalam derajat, jadi konversi implisit yang sangat singkat seperti Nils diposting sangat bagus.
Pada akhirnya, ini akan menjadi gula sintaksis, tetapi akan memiliki sedikit efek pada keterbacaan. Dan mungkin akan lebih mudah untuk menulis beberapa ekspresi juga (sin (180.0deg) lebih mudah untuk menulis daripada dosa (deg (180.0)) .Dan kemudian akan ada orang yang menyalahgunakan konsep tersebut. Tetapi kemudian, orang yang suka menggunakan bahasa harus menggunakan bahasa yang sangat restriktif daripada sesuatu yang ekspresif seperti C ++.
Ah, posting saya pada dasarnya tidak mengatakan apa-apa kecuali: itu akan baik-baik saja, dampaknya tidak akan terlalu besar. Jangan khawatir. :-)
sumber
Saya tidak pernah membutuhkan atau menginginkan fitur ini (tetapi ini bisa menjadi efek Blub ). Reaksi brengsek saya adalah lumpuh, dan cenderung menarik bagi orang yang sama yang berpikir bahwa itu keren untuk membebani operator + untuk operasi apa pun yang bisa ditafsirkan sebagai penambahan.
sumber
C ++ biasanya sangat ketat tentang sintaks yang digunakan - kecuali preprocessor tidak ada banyak yang dapat Anda gunakan untuk mendefinisikan sintaks / tata bahasa kustom. Misalnya kita dapat membebani operatos yang sudah ada, tetapi kita tidak dapat mendefinisikan yang baru - IMO ini sangat selaras dengan semangat C ++.
Saya tidak keberatan beberapa cara untuk kode sumber yang lebih khusus - tetapi titik yang dipilih tampaknya sangat terisolasi bagi saya, yang paling membingungkan saya.
Bahkan penggunaan yang dimaksudkan dapat membuat lebih sulit untuk membaca kode sumber: satu huruf mungkin memiliki efek samping luas yang sama sekali tidak dapat diidentifikasi dari konteksnya. Dengan simetri ke u, l dan f, sebagian besar pengembang akan memilih satu huruf.
Ini juga dapat mengubah pelingkupan menjadi masalah, menggunakan huruf tunggal di namespace global mungkin akan dianggap praktik yang buruk, dan alat yang seharusnya menggabungkan perpustakaan lebih mudah (ruang nama dan pengidentifikasi deskriptif) mungkin akan mengalahkan tujuannya.
Saya melihat beberapa manfaat dalam kombinasi dengan "otomatis", juga dalam kombinasi dengan perpustakaan unit seperti boost unit , tetapi tidak cukup untuk mendapatkan pujian ini.
Namun saya ingin tahu, ide pintar apa yang kita miliki.
sumber
using single letters in global namespace will probably be considered bad practice
Tetapi itu tidak memiliki relevansi: (A) UDL harus didefinisikan pada lingkup namespace (non-global) ... mungkin karena (B) mereka harus terdiri dari garis bawah kemudian> = 1 huruf, bukan hanya huruf, dan pengidentifikasi seperti di NS global dicadangkan untuk implementasi. Itu setidaknya 2 poin menentang gagasan bahwa UDL secara bawaan menghasilkan kebingungan. Adapun harus ruang lingkup namespace mengurangi utilitas fitur, itu sebabnya misalnya stdlib menyatakannya dalaminline namespace
s bahwa pengguna dapat mengimpor grosir jika diinginkan.Saya menggunakan literal pengguna untuk string biner seperti ini:
menggunakan
std::string(str, n)
konstruktor sehingga\0
tidak akan memotong tali menjadi dua. (Proyek ini melakukan banyak pekerjaan dengan berbagai format file.)Ini juga membantu ketika saya
std::string
menolak untuk pembungkusstd::vector
.sumber
Garis kebisingan dalam hal itu sangat besar. Juga mengerikan untuk dibaca.
Biarkan saya tahu, apakah mereka beralasan bahwa penambahan sintaks baru dengan jenis contoh? Misalnya, apakah mereka memiliki beberapa program yang sudah menggunakan C ++ 0x?
Bagi saya, bagian ini:
Tidak membenarkan bagian ini:
Bahkan jika Anda akan menggunakan sintaks-i dalam 1000 baris lain juga. Jika Anda menulis, Anda mungkin menulis 10.000 baris hal lain di sepanjang itu juga. Terutama ketika Anda mungkin masih akan menulis sebagian besar di mana-mana ini:
'auto' -keyword dapat dibenarkan, hanya mungkin. Tapi mari kita ambil C ++ saja, karena ini lebih baik daripada C ++ 0x dalam aspek ini.
Ini seperti .. sesederhana itu. Bahkan mengira semua kurung std dan runcing hanya timpang jika Anda menggunakannya di mana-mana. Saya tidak mulai menebak apa sintaks yang ada di C ++ 0x untuk mengubah std :: complex di bawah complex.
Itu mungkin sesuatu yang langsung, tapi saya tidak percaya itu sesederhana itu di C ++ 0x.
Mungkin? > :)
Pokoknya, intinya adalah: menulis 3.14i bukannya std :: complex (0, 3.14); tidak menghemat banyak waktu secara keseluruhan kecuali dalam beberapa kasus super khusus.
sumber
std::complex<double> val(0, 3.14);
.