C ++ 0x menunjukkan contoh menggunakan std::forward
:
template<class T>
void foo(T&& arg)
{
bar(std::forward<T>(arg));
}
Kapan menguntungkan untuk digunakan std::forward
, selalu?
Selain itu, harus digunakan &&
dalam deklarasi parameter, apakah valid dalam semua kasus? Saya pikir Anda harus memberikan temporari ke suatu fungsi jika fungsi tersebut dideklarasikan &&
dengannya, jadi bisakah foo dipanggil dengan parameter apa saja?
Terakhir, jika saya memiliki panggilan fungsi seperti ini:
template<int val, typename... Params>
void doSomething(Params... args) {
doSomethingElse<val, Params...>(args...);
}
Haruskah saya menggunakan ini sebagai gantinya:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
}
Juga, jika menggunakan parameter dua kali dalam fungsi, yaitu meneruskan ke dua fungsi pada saat yang sama, apakah bijaksana untuk menggunakannya std::forward
? Tidak akan std::forward
mengubah hal yang sama menjadi sementara dua kali, memindahkan memori dan membuatnya tidak valid untuk penggunaan kedua? Apakah kode berikut tidak masalah:
template<int val, typename... Params>
void doSomething(Params&&... args) {
doSomethingElse<val, Params...>(std::forward<Params>(args)...);
doSomethingWeird<val, Params...>(std::forward<Params>(args)...);
}
Saya agak bingung dengan std::forward
, dan saya dengan senang hati menggunakan beberapa kliring.
sumber
Args...&& args
?Jawaban Kerrek sangat berguna, tetapi tidak sepenuhnya menjawab pertanyaan dari judul:
Untuk menjawabnya, pertama-tama kita harus memperkenalkan gagasan tentang referensi universal . Scott Meyers memberikan nama ini dan saat ini mereka sering disebut referensi penerusan. Pada dasarnya, ketika Anda melihat sesuatu seperti ini:
ingatlah bahwa
param
itu bukan referensi nilai (karena orang mungkin tergoda untuk menyimpulkan), tetapi referensi universal *. Referensi universal dicirikan oleh bentuk yang sangat terbatas (hanyaT&&
, tanpa const atau kualifikasi yang serupa) dan dengan tipe deduksi - tipeT
akan dideduksi ketikaf
dipanggil. Singkatnya, referensi universal sesuai dengan referensi nilai jika mereka diinisialisasi dengan nilai-nilai, dan untuk menilai nilai referensi jika mereka diinisialisasi dengan nilai-nilai.Sekarang relatif mudah untuk menjawab pertanyaan awal - berlaku
std::forward
untuk:Contoh untuk kasus pertama:
Dalam kode di atas, kami tidak ingin
prop
memiliki nilai yang tidak diketahui setelahother.set(..)
selesai, jadi tidak ada penerusan yang terjadi di sini. Namun, ketika memanggilbar
kita majuprop
karena kita sudah selesai dengan itu danbar
dapat melakukan apa pun yang diinginkan dengan itu (misalnya memindahkannya).Contoh untuk kasus kedua:
Templat fungsi ini harus pindah
prop
ke nilai kembali jika itu adalah nilai dan salin jika itu adalah nilai. Jika kita dihilangkanstd::forward
pada akhirnya, kita akan selalu membuat salinan, yang lebih mahal ketikaprop
terjadi suatu nilai.* agar sepenuhnya tepat, referensi universal adalah konsep mengambil referensi nilai ke parameter templat cv-wajar tanpa pengecualian.
sumber
Apakah contoh ini membantu? Saya berjuang untuk menemukan contoh non generik yang berguna dari std :: forward, tetapi menemukan contoh rekening bank yang kami berikan uang tunai untuk disimpan sebagai argumen.
Jadi jika kita memiliki versi const dari sebuah akun, kita harus berharap ketika kita meneruskannya ke template setoran kita <> sehingga fungsi const dipanggil; dan ini kemudian melemparkan pengecualian (gagasan bahwa ini adalah akun yang terkunci!)
Jika kita memiliki akun non-const maka kita harus dapat mengubah akun.
Untuk membangun:
Output yang diharapkan:
sumber