Saya telah membaca di beberapa tempat berbeda bahwa menggunakan literal string baru C ++ 11 dimungkinkan untuk menghitung hash string pada waktu kompilasi. Namun, tampaknya tidak ada yang siap untuk keluar dan mengatakan bahwa itu akan mungkin atau bagaimana itu akan dilakukan.
- Apakah ini mungkin?
- Seperti apa rupa operatornya?
Saya sangat tertarik dengan kasus penggunaan seperti ini.
void foo( const std::string& value )
{
switch( std::hash(value) )
{
case "one"_hash: one(); break;
case "two"_hash: two(); break;
/*many more cases*/
default: other(); break;
}
}
Catatan: fungsi hash waktu kompilasi tidak harus terlihat persis seperti yang saya tulis. Saya melakukan yang terbaik untuk menebak seperti apa solusi akhirnya, tetapi meta_hash<"string"_meta>::value
juga bisa menjadi solusi yang layak.
c++
metaprogramming
c++11
hash
deft_code
sumber
sumber
Jawaban:
Ini agak terlambat, tetapi saya berhasil menerapkan fungsi CRC32 waktu kompilasi dengan menggunakan
constexpr
. Masalahnya adalah pada saat penulisan, ini hanya bekerja dengan GCC dan bukan kompiler MSVC atau Intel.Berikut ini cuplikan kodenya:
CrcVal01
sama dengan 0x335CC04ASemoga ini bisa membantu Anda!
sumber
constexpr
tidak tersedia di VS2013, kecuali pada November 2013 CTP blogs.msdn.com/b/vcblog/archive/2013/11/18/...Setidaknya dengan membaca §7.1.5 / 3 dan §5.19, berikut ini mungkin sah:
Ini tampaknya mengikuti aturan dasar dalam §7.1.5 / 3:
Ada beberapa pertanyaan apakah ini
*input
melibatkan konversi nilai l ilegal ke nilai r, dan saya tidak yakin saya memahami aturan di §5.19 / 2/6/2 1 dan §4.1 cukup baik untuk memastikannya.Dari sudut pandang praktis, kode ini diterima oleh (misalnya) g ++, setidaknya sejauh g ++ 4.7.1.
Penggunaannya akan seperti ini:
Untuk memenuhi persyaratan §5.19 / 2/6/2 Anda mungkin harus melakukan hal seperti ini:
sumber
constexpr
, 2: Anda tidak memiliki kondisi terputus-putus (di mana*input == nullptr
) dan seperti yang saya pahamiconstexpr
Anda tidak dapat memilikinya.(unsigned)-1
jika ada; dan mengembalikan 1 untuk semua string lainnya. Tulis ulang dengan operator bersyarat terner?Ini adalah upaya untuk menyelesaikan masalah OP secepat mungkin.
contoh hidup .
Perhatikan perbedaan utama -
std::hash
tidak dapat digunakan, karena kita tidak memiliki kendali atasstd::hash
algoritme, dan kita harus menerapkannya kembali sebagaiconstexpr
untuk mengevaluasinya pada waktu kompilasi. Selain itu, tidak ada hash "transparan" di dalamnyastd
, jadi Anda tidak bisa (tanpa membuatstd::string
) hash buffer karakter mentah sebagaistd::string
.Saya memasukkan
std::string
hasher khusus (denganconst char*
dukungan transparan ) ke dalammy_hash
namespace, sehingga Anda dapat menyimpannyastd::unordered_map
jika Anda membutuhkan konsistensi.Berdasarkan jawaban @JerryCoffin yang sangat baik dan utas komentar di bawahnya, tetapi dengan upaya untuk menulisnya dengan praktik terbaik C ++ 11 saat ini (bukan mengantisipasinya!).
Perhatikan bahwa menggunakan "hash mentah" untuk
switch
pernyataancase
itu berbahaya. Anda akan ingin melakukan==
perbandingan setelahnya untuk memastikannya berhasil.sumber
Cuplikan ini didasarkan pada Clement JACOB. Tapi bekerja dengan dentang juga. Dan itu harus lebih cepat dalam kompilasi (hanya memiliki satu panggilan rekursif, bukan dua seperti di posting asli).
Lihat bukti konsep di sini
sumber
Perhatikan bahwa formulir yang ditampilkan di sini tidak diterima ke dalam standar, seperti yang disebutkan di bawah.
Pemrosesan string waktu kompilasi diperkirakan menjadi mungkin melalui literal yang ditentukan pengguna yang diusulkan di N2765 .
Seperti yang telah saya sebutkan, saya tidak tahu ada kompilator yang saat ini mengimplementasikannya dan tanpa dukungan kompilator hanya ada dugaan kerja.
Dalam §2.13.7.3 dan 4 draf, kami memiliki yang berikut ini:
Gabungkan itu dengan
constexpr
dan kita harus memiliki pemrosesan string waktu kompilasi.update: saya mengabaikan bahwa saya membaca paragraf yang salah, formulir ini diizinkan untuk literal-integer-yang ditentukan pengguna dan -floating-literals, tetapi tampaknya tidak untuk -string-literal (§2.13.7.5).
Bagian dari proposal ini sepertinya belum diterima.
Yang sedang berkata, dengan pandangan terbatas saya pada C ++ 0x, mungkin terlihat seperti ini (kemungkinan besar saya salah):
Jika pendekatan Jerry berhasil, maka berikut ini seharusnya berhasil:
sumber
constexpr
literal yang ditentukan pengguna. Saya tidak yakin Anda dapat menggunakan string literal sebagai parameter template, bukankah mereka memiliki tautan statis? (setidaknya ada di C ++ 98 dan oleh karena itu verboten sebagai parameter template).operator ""_hash
berfungsi untuk saya di Xcode 5.0.2.Solusi lain berdasarkan Clement JACOB, menggunakan C ++ 11 constexpr (bukan C ++ 14 diperpanjang) tetapi hanya memiliki satu rekursi.
Beberapa penjelasan
combine_crc32
memungkinkan kita menyimpan hasil rekursi di bawah variabelpart
dan menggunakannya dua kali. Fungsi ini adalah panduan untuk batasan C ++ 11 yang melarang deklarasi variabel lokal.ctcrc32
Fungsi mengharapkan literal string, yang dilewatkan sebagaiconst char (&)[len]
. Dengan cara ini kita bisa mendapatkan panjang string sebagai parameter template dan tidak harus bergantung pada makro.sumber
Yang berikut ini berfungsi di GCC 4.6.1, dan Anda dapat menggunakan salah satu
hash
ataupack
di blok sakelar.GCC tampaknya (?) Tidak mengizinkan panggilan rekursif di mana kami meneruskan
s+1
dengans
pointer, itulah sebabnya saya menggunakanoff
variabel.sumber
Jika Anda memiliki compiler c ++ 17 dan string_view, ini menjadi sepele, cukup tulis versi normalnya:
sumber
crc32("mystring")
(biasanya VS cenderung melakukan itu). Trik untuk menghindari masalah itu adalah dengan membuat variabel constexpr yang bergantung pada evaluasi waktu kompilasi crc32 Anda. Biasanyaconstexpr uint32_t val = crc32("mystring");
Berikut adalah implementasi C ++ 11 lainnya (berdasarkan jawaban @ CygnusX1), yang bekerja dengan array karakter constexpr dan string runtime:
Anda perlu
str.size() + 1
karenalen
dalam kelebihan kedua adalahstrlen(str) + 1
karena karakter null di akhir.Saya tidak menambahkan kelebihan beban
const char *
karena mengacaukan kelebihan beban kedua - Anda dapat dengan mudah menambahkan beban berlebih untukconst char *, size_t
ataustd::string_view
.sumber
Ini pertanyaan yang bagus.
Berdasarkan jawaban Jerry Coffin, saya telah membuat yang lain yang kompatibel dengan std :: hash Visual Studio 2017.
https://github.com/manuelgustavo/cx_hash
sumber
Saya masih kehilangan varian crc32-literal (yang tidak dimungkinkan dengan template), jadi inilah saran saya berdasarkan CygnusX1 . Lakukan beberapa pengujian, silakan berikan umpan balik.
Testet di MSVC.
PS: Saya benci mencari hal tambahan di tempat lain, jadi saya menyalin tabel CRC di bagian bawah jawaban saya.
Alternatif dengan algoritme dari Dan Bernstein (djb2) (jawaban gabungan dari Jerry Coffin + Georg Fritzsche )
Tabel CRC32:
sumber