Apa kemampuan baru yang ditambahkan oleh literal yang ditetapkan pengguna ke C ++?

139

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 _ADdan _BCmembuat tanggal saya menemukan itu bermasalah karena pesanan operator. 1974/01/06_ADpertama akan mengevaluasi 1974/01(sebagai ints polos ) dan hanya kemudian 06_AD(untuk mengatakan apa-apa Agustus dan September harus ditulis tanpa 0alasan oktal). Ini dapat diatasi dengan membuat sintaks 1974-1/6_ADagar 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

Motti
sumber
8
Saya akan memilih untuk menutup ini. Judulnya sangat jelas inflamatory.
Puppy
76
@DeadMG, jika Anda memiliki masalah dengan judul Anda dapat mengeditnya. Agak lucu mencoba menutup pertanyaan berusia 3 tahun yang memiliki 11 upvote dan 8 favorit. (Tidak disebutkan bahwa etiket di situs ini telah berubah dalam 3 tahun terakhir).
Motti
5
Saya pikir Anda memiliki kesalahan dalam contoh Anda: string operator "" _s(const char*s);"tidak dapat digunakan untuk menguraikan "hello"_s". Ini adalah string literal dan akan mencari operator dengan size_tparameter tambahan . Apakah saya benar?
towi
1
Satu hal yang saya bertanya-tanya adalah apakah masuk akal untuk menulis "portable C" di C ++, mengganti tipe seperti uint16_tyang perilakunya bergantung pada implementasi, dengan tipe yang serupa uwrap16dan unum16yang perilakunya bebas implementasi, seperti yang diberikan uwrap16 w=1; unum16 n=1;ekspresi w-2dan n-2akan menghasilkan (uwrap16)65535dan (int)-1, masing-masing [ uint16_takan menghasilkan hasil pertama pada sistem di mana int16 bit, dan yang kedua pada sistem di mana intlebih besar]. Masalah terbesar yang saya lihat adalah menangani literal angka.
supercat
1
Mampu menggunakan literal literal untuk beroperasi secara lancar dengan tipe numerik perilaku tertentu lainnya akan tampak seperti memungkinkan jenis tersebut digunakan untuk membuat bahasa di mana kode yang ingin melakukan tindakan yang bergantung pada implementasi dapat melakukannya tanpa harus bergantung pada implementasi- perilaku yang didefinisikan. Ada beberapa tempat di mana IDB masih tidak dapat dihindari karena hal-hal seperti perbedaan pointer dan sizeofmengembalikan tipe integer yang bergantung pada implementasi, tetapi situasi masih dapat dibuat jauh lebih baik daripada sebelumnya. Apa yang akan Anda pikirkan tentang konsep itu?
supercat

Jawaban:

71

Inilah kasus di mana ada keuntungan menggunakan literal yang ditentukan pengguna alih-alih panggilan konstruktor:

#include <bitset>
#include <iostream>

template<char... Bits>
  struct checkbits
  {
    static const bool valid = false;
  };

template<char High, char... Bits>
  struct checkbits<High, Bits...>
  {
    static const bool valid = (High == '0' || High == '1')
                   && checkbits<Bits...>::valid;
  };

template<char High>
  struct checkbits<High>
  {
    static const bool valid = (High == '0' || High == '1');
  };

template<char... Bits>
  inline constexpr std::bitset<sizeof...(Bits)>
  operator"" _bits() noexcept
  {
    static_assert(checkbits<Bits...>::valid, "invalid digit in binary string");
    return std::bitset<sizeof...(Bits)>((char []){Bits..., '\0'});
  }

int
main()
{
  auto bits = 0101010101010101010101010101010101010101010101010101010101010101_bits;
  std::cout << bits << std::endl;
  std::cout << "size = " << bits.size() << std::endl;
  std::cout << "count = " << bits.count() << std::endl;
  std::cout << "value = " << bits.to_ullong() << std::endl;

  //  This triggers the static_assert at compile time.
  auto badbits = 2101010101010101010101010101010101010101010101010101010101010101_bits;

  //  This throws at run time.
  std::bitset<64> badbits2("2101010101010101010101010101010101010101010101010101010101010101_bits");
}

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).

emsr
sumber
7
Anda dapat melakukan hal yang sama dengan memberikan std :: bitset konstruktor constexpr yang tepat.
Nicol Bolas
1
@NicolBolas Anda benar. Aku benar-benar terkejut tidak ada di sana. Mungkin kita harus mengusulkan satu atau dua untuk 2014 jika belum terlambat.
emsr
192

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 ++:

// C89:
MyComplex z1 = { 1, 2 } ;

// C99: You'll note I is a macro, which can lead
// to very interesting situations...
double complex z1 = 1 + 2*I;

// C++:
std::complex<double> z1(1, 2) ;

// C++11: You'll note that "i" won't ever bother
// you elsewhere
std::complex<double> z1 = 1 + 2_i ;

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:

Point p = 25_x + 13_y + 3_z ; // 3D point

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:

css::Font::Size p0 = 12_pt ;       // Ok
css::Font::Size p1 = 50_percent ;  // Ok
css::Font::Size p2 = 15_px ;       // Ok
css::Font::Size p3 = 10_em ;       // Ok
css::Font::Size p4 = 15 ;         // ERROR : Won't compile !

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:

1974/01/06AD
    ^  ^  ^

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:

"1974-01-06"_AD ;   // ISO-like notation
"06/01/1974"_AD ;   // french-date-like notation
"jan 06 1974"_AD ;  // US-date-like notation
19740106_AD ;       // integer-date-like notation

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.

paercebal
sumber
1
Terima kasih, saya dan kepribadian alternatif saya yang lain telah ditemukan. Lebih serius, saya memang menulis ini sendirian, tetapi mungkin saya menggunakan beberapa ekspresi bahasa ibu saya dan mereka tidak menerjemahkan dengan baik ke bahasa Inggris.
paercebal
Adapun "bagian yang berbeda", seperti yang ditunjukkan oleh judul mereka, maaf, saya kira ini mengatur posting yang agak panjang. Adapun teks tebal, itu adalah ringkasan paragraf mereka. Orang-orang yang hanya menginginkan info tanpa pembenaran dapat membatasi pembacaan mereka pada judul dan teks tebal.
paercebal
3
+1. Penjelasan yang sangat bagus. Kami menunggu ini diimplementasikan. Ini sangat penting bagi kami. Kami bekerja pada MDE (Model-Driven Engineering) dan menemukan ini perlu. Saya menambahkan respons di bawah untuk menjelaskan kasus kami.
Diego Sevilla
9
@TGV:: you can write 1+2i, but you still can't write a+bi, so there's absolutely no pointBahkan mengabaikan a+bicontoh 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 menulis 1.5fdan 1000UL, mengapa Anda tidak bisa menulis 25iatau bahkan 100101b? Berlawanan dengan C dan Java, tipe pengguna tidak dianggap sebagai warga negara kelas dua bahasa di C ++.
paercebal
3
@Anton:: Most of data still comes from IOAda banyak nilai yang dikodekan dalam kode. Lihatlah semua boolean, semua bilangan bulat, semua ganda yang ada dalam kode, karena lebih mudah untuk menulis x = 2 * y ;daripada di x = Two * ymana 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.
paercebal
36

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.

double operator ""_deg(long double d)
{ 
    // returns radians
    return d*M_PI/180; 
}

Ini juga dapat digunakan untuk berbagai representasi titik tetap (yang masih digunakan di bidang DSP dan grafik).

int operator ""_fix(long double d)
{ 
    // returns d as a 1.15.16 fixed point number
    return (int)(d*65536.0f); 
}

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.

Nils Pipenbrinck
sumber
1
"Tapi kami sudah memiliki begitu banyak alat yang disalahgunakan sehingga satu lagi tidak terlalu sakit. " Wow, saya harap itu bukan filosofi di balik semua itu yang membuat banjir fitur c ++ [x] 1234567890 baru-baru ini. Bayangkan harus belajar perpustakaan yang menggunakan semua itu, ditambah sepuluh format file untuk konfigurasi dan dua alat untuk pra dan pasca pemrosesan kode Anda ...
masterxilo
@masterxilo Tentu saja, pada kenyataannya, contoh Anda tidak masuk akal: UDL tidak lebih sulit untuk dipelajari daripada fungsi, hanya sebagai sintaksis gula untuk mereka - & selain itu, lib yang baik hanya menggunakan fitur yang diperlukan untuk meningkatkan UX - & mendokumentasikan dengan tepat apa itu semua cara. Jika seseorang terlalu sering menggunakan fitur untuk menghasilkan kode yang tidak dapat dibaca (dengan asumsi itu bisa dihindari dalam pekerjaan mereka ...), itu tidak membuat fitur itu salah, hanya penggunaannya. Ditambah lagi, satu orang yang tidak dapat dibaca adalah roti dan mentega orang lain. Itu semua pendapat - & opsi . Jika Anda tidak menyukainya, jangan khawatir! Anda tidak harus menggunakannya. Yang lain bisa .
underscore_d
17

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 suntuk std::stringdan iuntuk 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.

coppro
sumber
Terima kasih telah menjelaskan tentang ruang nama ... Saya ingin tahu itu.
Nathan Reed
12

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:

typedef ::ecore::Class< Attribute<int>, Attribute<int> > MyClass;

Namun, ternyata setiap elemen dalam suatu model atau metamodel, biasanya memiliki nama. Kami ingin menulis:

typedef ::ecore::Class< "MyClass", Attribute< "x", int>, Attribute<"y", int> > MyClass;

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):

typedef ::ecore::Class< MyClass_n, Attribute< x_n, int>, Attribute<y_n, int> > MyClass;

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.

Diego Sevilla
sumber
4
Saya suka sangat sangat banyak yang by the compiler at compile timebagian ... :-)
paercebal
12

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:

  1. 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.

  2. 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).

  3. 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).

  4. 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.

tukang batu
sumber
9

Mendukung pemeriksaan dimensi waktu kompilasi adalah satu-satunya pembenaran yang diperlukan.

auto force = 2_N; 
auto dx = 2_m; 
auto energy = force * dx; 

assert(energy == 4_J); 

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.

Martin Moene
sumber
Atau lihat unit , analisis dimensi, waktu kompilasi, hanya header, dan konversi unit dibangun di atas c ++ 14 tanpa dependensi oleh Nic Holthaus .
Martin Moene
6

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

assert(1_kg == 2.2_lb); // give or take 0.00462262 pounds

... Saya ingin tahu bagaimana Anda mengekspresikannya hari ini. Anda akan memiliki kelas KG dan LB dan Anda akan membandingkan objek implisit:

assert(KG(1.0f) == LB(2.2f));

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. :-)

mstrobl
sumber
5
Tanda kurung Anda tidak seimbang! Maaf, OCD saya juga membenciku.
X-Istence
3

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.

fizzer
sumber
Saya mengkonfirmasi: Artikel yang sangat menarik.
paercebal
2

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.

Peterchen
sumber
1
using single letters in global namespace will probably be considered bad practiceTetapi 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 dalam inline namespaces bahwa pengguna dapat mengimpor grosir jika diinginkan.
underscore_d
2

Saya menggunakan literal pengguna untuk string biner seperti ini:

 "asd\0\0\0\1"_b

menggunakan std::string(str, n)konstruktor sehingga \0tidak akan memotong tali menjadi dua. (Proyek ini melakukan banyak pekerjaan dengan berbagai format file.)

Ini juga membantu ketika saya std::stringmenolak untuk pembungkus std::vector.

rr-
sumber
-5

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:

auto val = 3.14_i

Tidak membenarkan bagian ini:

std::complex<double> operator ""_i(long double d) // cooked form
{ 
    return std::complex(0, d);
}

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:

std::complex<double> val = 3.14i

'auto' -keyword dapat dibenarkan, hanya mungkin. Tapi mari kita ambil C ++ saja, karena ini lebih baik daripada C ++ 0x dalam aspek ini.

std::complex<double> val = std::complex(0, 3.14);

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.

complex = std::complex<double>;

Itu mungkin sesuatu yang langsung, tapi saya tidak percaya itu sesederhana itu di C ++ 0x.

typedef std::complex<double> complex;

complex val = std::complex(0, 3.14);

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.

Riang
sumber
10
@Cheery: Untuk Anda, "auto val = 3.14i" tidak membenarkan kode yang ditulis untuk mendukungnya. Saya dapat menjawab bahwa, bagi saya "printf ("% i ", 25)" tidak membenarkan kode yang ditulis untuk printf. Apakah Anda melihat pola?
paercebal
5
@Cheery: "Garis kebisingan dalam hal itu sangat besar". Tidak, ini bukan ... "Juga mengerikan membaca". Argumen subyektif Anda menarik, tetapi Anda harus melihat pada operator kelebihan secara umum untuk melihat kode untuk fitur ini jauh dari mengejutkan / mengejutkan ... Untuk pengembang C ++
paercebal
3
otomatis akan membantu keterbacaan. pertimbangkan untuk menggunakan interator dalam for loop: for (auto it = vec.begin (); it! = vec.end (); ++ it) ... Saya tahu tentang for_each, tetapi tidak suka harus membuat functor untuk menggunakannya .
KitsuneYMG
1
@ kts: Dengan C ++ 1x kita akan memiliki lambda dan jangkauan untuk
Joe D
3
Jika baris C ++ Anda lebih baik dari C ++ 0x, maka baris saya lebih baik. Menulis hanya: std::complex<double> val(0, 3.14);.
Ben Voigt