Apa saja penjelasan yang baik tentang apa pencarian bergantung pada argumen? Banyak orang juga menyebutnya Koenig Lookup juga.
Lebih disukai saya ingin tahu:
- Mengapa ini hal yang baik?
- Kenapa itu hal yang buruk?
- Bagaimana cara kerjanya?
c++
argument-dependent-lookup
name-lookup
c++-faq
pengguna965369
sumber
sumber
std::cout << "Hello world";
tidak akan dikompilasiJawaban:
Koenig Lookup , atau Argument Dependent Lookup , menjelaskan bagaimana nama yang tidak memenuhi syarat dicari oleh kompiler di C ++.
Standar C ++ 11 § 3.4.2 / 1 menyatakan:
Dalam istilah yang lebih sederhana, Nicolai Josuttis menyatakan 1 :
Contoh kode sederhana:
Dalam contoh di atas tidak ada
using
-deklarasi atau -direktifusing
tetapi masih kompiler dengan benar mengidentifikasi nama yang tidak memenuhi syaratdoSomething()
sebagai fungsi yang dinyatakan dalam namespaceMyNamespace
dengan menerapkan pencarian Koenig .Bagaimana cara kerjanya?
Algoritma memberitahu kompiler untuk tidak hanya melihat lingkup lokal, tetapi juga ruang nama yang berisi tipe argumen. Jadi, dalam kode di atas, kompiler menemukan bahwa objek
obj
, yang merupakan argumen fungsidoSomething()
, adalah milik namespaceMyNamespace
. Jadi, terlihat di namespace itu untuk menemukan deklarasidoSomething()
.Apa keuntungan dari pencarian Koenig?
Seperti yang ditunjukkan contoh kode sederhana di atas, pencarian Koenig memberikan kemudahan dan kemudahan penggunaan bagi programmer. Tanpa pencarian Koenig akan ada overhead pada programmer, untuk berulang kali menentukan nama-nama yang memenuhi syarat, atau sebaliknya, menggunakan banyak
using
-deklarasian.Mengapa kritik terhadap pencarian Koenig?
Ketergantungan yang berlebihan pada pencarian Koenig dapat menyebabkan masalah semantik, dan terkadang membuat programmer lengah.
Pertimbangkan contoh
std::swap
, yang merupakan algoritma perpustakaan standar untuk bertukar dua nilai. Dengan pencarian Koenig kita harus berhati-hati saat menggunakan algoritma ini karena:mungkin tidak menunjukkan perilaku yang sama dengan:
Dengan ADL, versi mana dari
swap
fungsi mana yang dipanggil akan bergantung pada namespace argumen yang diteruskan ke sana.Jika ada namespace
A
dan jikaA::obj1
,A::obj2
&A::swap()
ada maka contoh kedua akan menghasilkan panggilan keA::swap()
, yang mungkin bukan yang diinginkan pengguna.Selanjutnya, jika karena alasan kedua
A::swap(A::MyClass&, A::MyClass&)
danstd::swap(A::MyClass&, A::MyClass&)
didefinisikan, maka contoh pertama akan memanggilstd::swap(A::MyClass&, A::MyClass&)
tapi yang kedua tidak akan dikompilasi karenaswap(obj1, obj2)
akan ambigu.Hal sepele:
Kenapa disebut "Koenig lookup"?
Karena itu dirancang oleh mantan AT&T dan peneliti dan programmer Bell Labs, Andrew Koenig .
Bacaan lebih lanjut:
Pencarian Nama Herb Sutter di GotW
Standar C ++ 03/11 [basic.lookup.argdep]: 3.4.2 Pencarian nama yang bergantung pada argumen.
1 Definisi pencarian Koenig adalah seperti yang didefinisikan dalam buku Josuttis, The C ++ Standard Library: A Tutorial and Reference .
sumber
std::swap
Anda benar-benar harus melakukan itu karena satu-satunya alternatif adalah menambahkanstd::swap
fungsi template spesialisasi eksplisit untukA
kelas Anda . Namun jikaA
kelas Anda adalah templat itu sendiri, itu akan menjadi spesialisasi parsial daripada spesialisasi eksplisit. Dan sebagian spesialisasi fungsi templat tidak diperbolehkan. Menambahkan kelebihanstd::swap
akan menjadi alternatif tetapi dilarang secara eksplisit (Anda tidak boleh menambahkan sesuatu kestd
namespace). Jadi ADL adalah satu-satunya cara untukstd::swap
.std::swap()
sepertinya agak mundur. Saya mengharapkan masalah yang terjadi ketikastd::swap()
dipilih daripada kelebihan spesifik untuk tipeA::swap()
,. Contoh denganstd::swap(A::MyClass&, A::MyClass&)
sepertinya menyesatkan. karenastd
tidak akan pernah memiliki kelebihan spesifik untuk tipe pengguna, saya tidak berpikir itu adalah contoh yang bagus.MyNamespace::doSomething
, bukan hanya::doSomething
.Di Koenig Lookup, jika suatu fungsi dipanggil tanpa menentukan namespace-nya, maka nama fungsi juga dicari di namespace (s) di mana tipe argumen didefinisikan. Itu sebabnya juga dikenal sebagai nama pencarian Argument-Dependent , singkatnya hanya ADL .
Itu karena Koenig Lookup, kita dapat menulis ini:
Kalau tidak, kita harus menulis:
yang benar-benar terlalu banyak mengetik dan kode terlihat sangat jelek!
Dengan kata lain, dengan tidak adanya Koenig Lookup, bahkan program Hello World terlihat rumit.
sumber
std::cout
ini adalah satu argumen untuk fungsi tersebut, yang cukup untuk mengaktifkan ADL. Apakah kamu memperhatikan itu?ostream<<
(seperti apa yang diperlukan sebagai argumen dan apa yang dikembalikan). 2) Nama yang sepenuhnya memenuhi syarat (sepertistd::vector
ataustd::operator<<
). 3) Studi yang lebih rinci tentang Argument Dependent Lookup.std::endl
sebagai argumen, sebenarnya adalah fungsi anggota. Lagi pula, jika saya menggunakan"\n"
alih-alihstd::endl
, maka jawaban saya sudah benar. Terima kasih atas komentarnya.f(a,b)
memanggil fungsi gratis . Jadi dalam halstd::operator<<(std::cout, std::endl);
, tidak ada fungsi bebas seperti itu yang mengambilstd::endl
argumen kedua. Ini adalah fungsi anggota yang mengambilstd::endl
sebagai argumen, dan untuk itulah Anda harus menulisstd::cout.operator<<(std::endl);
. dan karena ada fungsi bebas yangchar const*
menjadi argumen kedua,"\n"
berfungsi;'\n'
akan bekerja juga.Mungkin yang terbaik adalah memulai dengan alasannya, dan baru kemudian menuju ke caranya.
Ketika ruang nama diperkenalkan, idenya adalah untuk memiliki segalanya didefinisikan dalam ruang nama, sehingga perpustakaan yang terpisah tidak saling mengganggu. Namun itu menimbulkan masalah dengan operator. Lihat misalnya pada kode berikut:
Tentu saja Anda bisa menulis
N::operator++(x)
, tetapi itu akan mengalahkan seluruh titik kelebihan operator. Oleh karena itu solusi harus ditemukan yang memungkinkan kompiler untuk menemukanoperator++(X&)
terlepas dari kenyataan bahwa itu tidak dalam ruang lingkup. Di sisi lain, masih tidak harus menemukan yang lainoperator++
didefinisikan dalam ruang nama lain yang tidak terkait yang dapat membuat panggilan ambigu (dalam contoh sederhana ini, Anda tidak akan mendapatkan ambiguitas, tetapi dalam contoh yang lebih kompleks, Anda mungkin). Solusinya adalah Argument Dependent Lookup (ADL), disebut demikian karena pencarian tergantung pada argumen (lebih tepatnya, pada tipe argumen). Karena skema ini ditemukan oleh Andrew R. Koenig, itu juga sering disebut pencarian Koenig.Kuncinya adalah bahwa untuk panggilan fungsi, selain pencarian nama normal (yang menemukan nama dalam lingkup pada titik penggunaan), dilakukan pencarian kedua dalam lingkup jenis argumen yang diberikan ke fungsi. Jadi dalam contoh di atas, jika Anda menulis
x++
di utama, tampaknya untukoperator++
tidak hanya di lingkup global, tetapi juga dalam lingkup di mana jenisx
,N::X
, didefinisikan, yaitu dinamespace N
. Dan di sana ia menemukan yang cocokoperator++
, dan karena itux++
berfungsi. Namun, yangoperator++
didefinisikan di namespace lainN2
tidak akan ditemukan. Karena ADL tidak terbatas pada ruang nama, Anda juga dapat menggunakanf(x)
bukannyaN::f(x)
dimain()
.sumber
Tidak semuanya baik, menurut saya. Orang-orang, termasuk vendor penyusun, telah menghinanya karena perilakunya yang terkadang tidak menguntungkan.
ADL bertanggung jawab untuk perombakan besar untuk for-range loop di C ++ 11. Untuk memahami mengapa ADL kadang-kadang dapat memiliki efek yang tidak diinginkan, pertimbangkan bahwa tidak hanya ruang nama tempat argumen didefinisikan dipertimbangkan, tetapi juga argumen argumen templat argumen, dari tipe parameter tipe fungsi / pointee jenis tipe pointer dari argumen tersebut , dan sebagainya.
Contoh menggunakan boost
Ini menghasilkan ambiguitas jika pengguna menggunakan perpustakaan boost.range, karena keduanya
std::begin
ditemukan (menggunakan ADLstd::vector
) danboost::begin
ditemukan (menggunakan ADLboost::shared_ptr
).sumber
std::begin
menghapus ambiguitas namespace.