Saya menemukan bahwa lvalue
penutupan lambda selalu dapat dilewati sebagai rvalue
parameter fungsi.
Lihat demonstrasi sederhana berikut.
#include <iostream>
#include <functional>
using namespace std;
void foo(std::function<void()>&& t)
{
}
int main()
{
// Case 1: passing a `lvalue` closure
auto fn1 = []{};
foo(fn1); // works
// Case 2: passing a `lvalue` function object
std::function<void()> fn2 = []{};
foo(fn2); // compile error
return 0;
}
Kasus 2 adalah perilaku standar (saya hanya menggunakan std::function
untuk tujuan demonstrasi, tetapi jenis lainnya akan berperilaku sama).
Bagaimana dan mengapa kasus 1 berfungsi? Bagaimana keadaan fn1
penutupan setelah fungsi kembali?
fn1
secara implisit dikonversi kestd::function
dalamfoo(fn1)
. Fungsi sementara itu adalah nilai.std::function
diambil dari lambda". Program Anda tidak berupaya menyimpulkan argumen templatstd::function
, jadi tidak ada masalah dengan konversi implisit.std::function
memiliki konstruktor non-eksplisit yang menerima penutupan lambda, sehingga ada konversi implisit. Tetapi dalam keadaan pertanyaan terkait, instantiasi templatestd::function
tidak dapat disimpulkan dari jenis lambda. (Misalnyastd::function<void()>
dapat dibangun dari[](){return 5;}
meskipun memiliki jenis kembali tidak batal.Jawaban:
Meminta
foo
membutuhkan instancestd::function<void()>
yang mengikat referensi nilai .std::function<void()>
dapat dibangun dari objek yang dapat dipanggil yang kompatibel denganvoid()
tanda tangan.Pertama,
std::function<void()>
objek sementara dibangun dari[]{}
. Konstruktor yang digunakan adalah # 5 di sini , yang menyalin penutupan kestd::function
instance:Kemudian,
function
instance sementara terikat pada referensi nilai.Sama seperti sebelumnya, karena disalin ke
std::function
instance. Penutupan asli tidak terpengaruh.sumber
Lambda bukan a
std::function
. Referensi tidak mengikat secara langsung .Kasus 1 berfungsi karena lambdas dapat dikonversi menjadi
std::function
s. Ini berarti bahwa suatu sementarastd::function
diwujudkan dengan menyalinfn1
. Kata sementara dapat diikat ke referensi nilai, dan argumen cocok dengan parameter.Dan penyalinan juga mengapa
fn1
sama sekali tidak terpengaruh oleh apa pun yang terjadi difoo
.sumber
fn1
tidak memiliki kewarganegaraan, karena tidak menangkap apa pun.Ini berfungsi karena argumennya bertipe berbeda dari jenis yang dirujuk. Karena memiliki tipe yang berbeda, konversi implisit dipertimbangkan. Karena lambda adalah Callable untuk argumen ini
std::function
, maka secara implisit dapat dikonversi untuk itu melalui template yang mengkonversi konstruktorstd::function
. Hasil konversi adalah nilai awal, dan dengan demikian dapat diikat dengan referensi nilai.sumber