Saya punya beberapa pertanyaan tentang program ini:
#include <iostream>
#include <type_traits>
#include <functional>
using namespace std;
template <typename T> void foo ( T x )
{
auto r=ref(x);
cout<<boolalpha;
cout<<is_same<T&,decltype(r)>::value;
}
int main()
{
int x=5;
foo (x);
return 0;
}
Outputnya adalah:
false
Saya ingin tahu, jika std::ref
tidak mengembalikan referensi suatu objek, lalu apa fungsinya? Pada dasarnya apa perbedaan antara:
T x;
auto r = ref(x);
dan
T x;
T &y = x;
Juga, saya ingin tahu mengapa perbedaan ini ada? Mengapa kita membutuhkan std::ref
atau std::reference_wrapper
ketika kita memiliki referensi (yaitu T&
)?
x = y;
kedua kasus tersebut?Jawaban:
Well
ref
membangun sebuah objek denganreference_wrapper
tipe yang sesuai untuk menampung referensi ke sebuah objek. Yang artinya saat Anda melamar:auto r = ref(x);
Ini mengembalikan a
reference_wrapper
dan bukan referensi langsung kex
(yaituT&
). Inireference_wrapper
(yaitur
) sebagai gantinya berlakuT&
.A
reference_wrapper
sangat berguna ketika Anda ingin menirureference
objek yang dapat disalin (keduanya dapat dikopi-konstruktif dan dapat dialihkan ).Dalam C ++, setelah Anda membuat referensi (katakanlah
y
) ke obyek (katakanlahx
), kemudiany
danx
berbagi sama alamat dasar . Selain itu,y
tidak dapat merujuk ke objek lain. Anda juga tidak dapat membuat array referensi, misalnya kode seperti ini akan menimbulkan kesalahan:#include <iostream> using namespace std; int main() { int x=5, y=7, z=8; int& arr[] {x,y,z}; // error: declaration of 'arr' as array of references return 0; }
Namun ini legal:
#include <iostream> #include <functional> // for reference_wrapper using namespace std; int main() { int x=5, y=7, z=8; reference_wrapper<int> arr[] {x,y,z}; for (auto a: arr) cout << a << " "; return 0; } /* OUTPUT: 5 7 8 */
Berbicara tentang masalah Anda dengan
cout << is_same<T&,decltype(r)>::value;
, solusinya adalah:cout << is_same<T&,decltype(r.get())>::value; // will yield true
Mari saya tunjukkan sebuah program:
#include <iostream> #include <type_traits> #include <functional> using namespace std; int main() { cout << boolalpha; int x=5, y=7; reference_wrapper<int> r=x; // or auto r = ref(x); cout << is_same<int&, decltype(r.get())>::value << "\n"; cout << (&x==&r.get()) << "\n"; r=y; cout << (&y==&r.get()) << "\n"; r.get()=70; cout << y; return 0; } /* Ouput: true true true 70 */
Lihat di sini kita mengetahui tiga hal:
Sebuah
reference_wrapper
objek (di sinir
) dapat digunakan untuk membuat array referensi yang tidak memungkinkanT&
.r
sebenarnya bertindak seperti referensi nyata (lihat bagaimanar.get()=70
mengubah nilaiy
).r
tidak samaT&
tetapir.get()
. Ini berarti bahwar
holdingT&
seperti namanya adalah pembungkus di sekitar referensiT&
.Saya harap jawaban ini lebih dari cukup untuk menjelaskan keraguan Anda.
sumber
reference_wrapper
dapat ditetapkan ulang , tetapi tidak dapat "menyimpan referensi ke lebih dari satu objek". 2/3: Poin yang adil tentang di mana.get()
yang sesuai - tetapi tidak bercampurr
dapat digunakan sama sepertiT&
dalam kasus di manar
konversioperator
dapat dipanggil dengan jelas - jadi tidak perlu memanggil.get()
dalam banyak kasus, termasuk beberapa dalam kode Anda (yang sulit dibaca karena kurangnya ruang).reference_wrapper
dapat menyimpan berbagai referensi jika Anda tidak yakin maka Anda dapat mencobanya sendiri. Plus.get()
digunakan ketika Anda ingin mengubah nilai objek yangreference_wrapper
dipegang` yaitur=70
ilegal sehingga Anda harus menggunakannyar.get()=70
. Coba sendiri !!!!!!int a[4]{1, 2, 3, 4}; int (&b)[4] = a;
? reference_wrapper tidak istimewa di sini sejak asliT&
tidak bekerja.wrapper
kaleng masuk dalam wadah. Ini berguna, tapi saya pikir orang salah menafsirkan ini sebagai lebih maju daripada yang sebenarnya. Jika saya menginginkan sebuah array dari 'refs', saya biasanya melewatkan perantara denganvector<Item *>
, itulahwrapper
intinya ... dan berharap anti-pointer purists tidak menemukan saya. Kasus penggunaan yang meyakinkan untuk itu berbeda dan lebih kompleks.std::reference_wrapper
dikenali oleh fasilitas standar untuk dapat melewatkan objek dengan referensi dalam konteks nilai-demi-nilai.Misalnya,
std::bind
dapat menerimastd::ref()
ke sesuatu, mengirimkannya berdasarkan nilai, dan mengekstraknya kembali menjadi referensi nanti.void print(int i) { std::cout << i << '\n'; } int main() { int i = 10; auto f1 = std::bind(print, i); auto f2 = std::bind(print, std::ref(i)); i = 20; f1(); f2(); }
Cuplikan ini menghasilkan:
10 20
Nilai
i
telah disimpan (diambil oleh nilai) kef1
dalam titik inisialisasi, tetapif2
telah disimpanstd::reference_wrapper
oleh nilai, dan dengan demikian berperilaku seperti yang diambil di fileint&
.sumber
std::ref(T)
mengembalikan astd::reference_wrapper
. Ini sedikit lebih dari sebuah pointer yang dibungkus, tetapi dikenali oleh perpustakaan sebagai "hei, saya seharusnya menjadi referensi! Tolong ubah saya kembali menjadi satu setelah Anda selesai melewati saya".Referensi (
T&
atauT&&
) adalah elemen khusus dalam bahasa C ++. Ini memungkinkan untuk memanipulasi objek dengan referensi dan memiliki kasus penggunaan khusus dalam bahasa tersebut. Misalnya, Anda tidak dapat membuat penampung standar untuk menyimpan referensi:vector<T&>
bentuknya tidak bagus dan menghasilkan kesalahan kompilasi.A
std::reference_wrapper
di sisi lain adalah objek C ++ yang dapat menampung referensi. Dengan demikian, Anda dapat menggunakannya dalam wadah standar.std::ref
adalah fungsi standar yang mengembalikan astd::reference_wrapper
pada argumennya. Dalam ide yang sama,std::cref
kembalistd::reference_wrapper
ke referensi const.Salah satu properti yang menarik dari a
std::reference_wrapper
, adalah memilikioperator T& () const noexcept;
. Itu berarti bahwa meskipun itu adalah objek yang sebenarnya , itu dapat secara otomatis diubah menjadi referensi yang dipegangnya. Begitu:operator T& () const noexcept;
, ini dapat digunakan di mana pun Anda dapat menggunakan referensi, karena itu akan secara otomatis dikonversi ke dalamnya.sumber
operator T& ()
2 jawaban lainnya yang gagal disebutkan.