Saya mencoba membuat vektor lambda, tetapi gagal:
auto ignore = [&]() { return 10; }; //1
std::vector<decltype(ignore)> v; //2
v.push_back([&]() { return 100; }); //3
Sampai baris # 2, kompilasi baik-baik saja . Tetapi baris # 3 memberikan kesalahan kompilasi :
kesalahan: tidak ada fungsi yang cocok untuk panggilan ke 'std :: vector <main () :: <lambda () >> :: push_back (main () :: <lambda ()>)'
Saya tidak ingin vektor penunjuk fungsi atau vektor objek fungsi. Namun, vektor objek fungsi yang merangkum ekspresi lambda nyata , akan bekerja untuk saya. Apakah ini mungkin?
Jawaban:
Setiap lambda memiliki jenis yang berbeda — meskipun memiliki tanda tangan yang sama. Anda harus menggunakan wadah enkapsulasi run-time seperti
std::function
jika Anda ingin melakukan sesuatu seperti itu.misalnya:
std::vector<std::function<int()>> functors; functors.push_back([&] { return 100; }); functors.push_back([&] { return 10; });
sumber
std::function<int()
, dapatkah saya menggunakan prototipe fungsi yang berbeda?vector
penyimpanan keduanyastd::function
danstd::string
?' Dan jawabannya sama: Tidak, karena itu bukan tujuan penggunaan. Anda dapat menggunakan kelas gaya 'varian' untuk melakukan penghapusan jenis yang cukup untuk meletakkan hal-hal yang berbeda dalam wadah, sambil menyertakan metode bagi pengguna untuk menentukan jenis 'nyata' dan karenanya memilih apa yang harus dilakukan (misalnya bagaimana memanggil) setiap elemen ... tetapi sekali lagi, mengapa terlalu jauh? Apakah ada alasan yang nyata?Semua ekspresi lambda memiliki jenis yang berbeda, meskipun keduanya identik karakter demi karakter . Anda mendorong lambda dari tipe yang berbeda (karena itu ekspresi lain) ke dalam vektor, dan itu jelas tidak akan berhasil.
Salah satu solusinya adalah membuat vektor
std::function<int()>
sebagai gantinya.auto ignore = [&]() { return 10; }; std::vector<std::function<int()>> v; v.push_back(ignore); v.push_back([&]() { return 100; });
Di catatan lain, sebaiknya gunakan
[&]
saat Anda tidak sedang mengambil gambar apa pun.sumber
()
lambda yang tidak membutuhkan argumen.Sementara apa yang dikatakan orang lain relevan, masih mungkin untuk mendeklarasikan dan menggunakan vektor lambda, meskipun itu tidak terlalu berguna:
auto lambda = [] { return 10; }; std::vector<decltype(lambda)> vec; vec.push_back(lambda);
Jadi, Anda dapat menyimpan sejumlah lambda di sana, selama itu adalah salinan / pemindahan
lambda
!sumber
Jika lambda Anda tidak memiliki kewarganegaraan, misalnya
[](...){...}
, C ++ 11 memungkinkannya untuk diturunkan menjadi penunjuk fungsi. Secara teori, kompiler yang memenuhi C ++ 11 akan dapat mengkompilasi ini:auto ignore = []() { return 10; }; //1 note misssing & in []! std::vector<int (*)()> v; //2 v.push_back([]() { return 100; }); //3
sumber
auto ignore = *[] { return 10; };
akan membuatignore
sebuahint(*)()
.explicit
, dereferensi ekspresi lambda adalah valid dan dereferensi penunjuk yang dihasilkan dari konversi. Kemudian menggunakanauto
decays referensi itu kembali menjadi sebuah pointer. (Menggunakanauto&
atauauto&&
akan menyimpan referensi.)()
disengaja atau tidak disengaja?Anda dapat menggunakan fungsi penghasil lambda (diperbarui dengan perbaikan yang disarankan oleh Nawaz):
#include <vector> #include <iostream> int main() { auto lambda_gen = [] (int i) {return [i](int x){ return i*x;};} ; using my_lambda = decltype(lambda_gen(1)); std::vector<my_lambda> vec; for(int i = 0; i < 10; i++) vec.push_back(lambda_gen(i)); int i = 0; for (auto& lambda : vec){ std::cout << lambda(i) << std::endl; i++; } }
Tapi saya pikir Anda pada dasarnya membuat kelas Anda sendiri pada saat ini. Sebaliknya jika lambda memiliki caputres / args yang sangat berbeda, dll. Anda mungkin harus menggunakan tupel.
sumber
lambda_gen
yang pada gilirannya bisa menjadi lambda itu sendiri. Namun,auto a = lambda_gen(1);
lakukan panggilan yang tidak perlu, yang dapat dihindari jika kita menulis inidecltype(lambda_gen(1))
.decltype
tidak dievaluasi , jadi panggilan tidak benar-benar dibuat. Kasus yang sama juga terjadisizeof
. Selain itu, kode ini tidak akan berfungsi di C ++ 11 bahkan jika Anda menambahkan tipe pengembalian trailing !!Setiap lambda memiliki tipe yang berbeda. Anda harus menggunakan
std::tuple
bukanstd::vector
.sumber