Apa yang dimaksud dengan ekspresi lambda di C ++ 11? Kapan saya akan menggunakannya? Kelas masalah apa yang mereka pecahkan yang tidak mungkin dilakukan sebelum perkenalan mereka?
Beberapa contoh, dan kasus penggunaan akan bermanfaat.
Apa yang dimaksud dengan ekspresi lambda di C ++ 11? Kapan saya akan menggunakannya? Kelas masalah apa yang mereka pecahkan yang tidak mungkin dilakukan sebelum perkenalan mereka?
Beberapa contoh, dan kasus penggunaan akan bermanfaat.
Jawaban:
C ++ termasuk fungsi generik yang berguna seperti std::for_each
dan std::transform
, yang bisa sangat berguna. Sayangnya mereka juga bisa sangat rumit untuk digunakan, terutama jika functor yang ingin Anda terapkan adalah unik untuk fungsi tertentu.
#include <algorithm>
#include <vector>
namespace {
struct f {
void operator()(int) {
// do something
}
};
}
void func(std::vector<int>& v) {
f f;
std::for_each(v.begin(), v.end(), f);
}
Jika Anda hanya menggunakan f
satu kali dan di tempat tertentu itu tampaknya sulit untuk menulis seluruh kelas hanya untuk melakukan sesuatu yang sepele dan satu.
Di C ++ 03 Anda mungkin tergoda untuk menulis sesuatu seperti berikut, untuk menjaga functor lokal:
void func2(std::vector<int>& v) {
struct {
void operator()(int) {
// do something
}
} f;
std::for_each(v.begin(), v.end(), f);
}
namun ini tidak diperbolehkan, f
tidak bisa diteruskan ke fungsi templat di C ++ 03.
C ++ 11 memperkenalkan lambdas memungkinkan Anda untuk menulis fungsi inline, anonim untuk menggantikan struct f
. Untuk contoh-contoh kecil yang sederhana, ini bisa lebih bersih untuk dibaca (itu membuat semuanya di satu tempat) dan berpotensi lebih mudah untuk dipertahankan, misalnya dalam bentuk paling sederhana:
void func3(std::vector<int>& v) {
std::for_each(v.begin(), v.end(), [](int) { /* do something here*/ });
}
Fungsi Lambda hanyalah gula sintaksis untuk functor anonim.
Dalam kasus sederhana, tipe pengembalian lambda disimpulkan untuk Anda, misalnya:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) { return d < 0.00001 ? 0 : d; }
);
}
namun ketika Anda mulai menulis lambda yang lebih kompleks, Anda akan dengan cepat menemukan kasus di mana tipe pengembalian tidak dapat disimpulkan oleh kompiler, misalnya:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
Untuk mengatasi ini, Anda diizinkan untuk secara eksplisit menentukan jenis pengembalian untuk fungsi lambda, menggunakan -> T
:
void func4(std::vector<double>& v) {
std::transform(v.begin(), v.end(), v.begin(),
[](double d) -> double {
if (d < 0.0001) {
return 0;
} else {
return d;
}
});
}
Sejauh ini kami belum menggunakan apa pun selain apa yang diteruskan ke lambda di dalamnya, tetapi kami juga dapat menggunakan variabel lain, dalam lambda. Jika Anda ingin mengakses variabel lain, Anda dapat menggunakan klausa tangkap ( []
ekspresi), yang sejauh ini belum digunakan dalam contoh-contoh ini, misalnya:
void func5(std::vector<double>& v, const double& epsilon) {
std::transform(v.begin(), v.end(), v.begin(),
[epsilon](double d) -> double {
if (d < epsilon) {
return 0;
} else {
return d;
}
});
}
Anda dapat menangkap dengan referensi dan nilai, yang dapat Anda tentukan menggunakan &
dan =
masing - masing:
[&epsilon]
ditangkap dengan referensi[&]
menangkap semua variabel yang digunakan dalam lambda dengan referensi[=]
menangkap semua variabel yang digunakan dalam lambda berdasarkan nilai[&, epsilon]
menangkap variabel seperti dengan [&], tetapi dengan nilai epsilon[=, &epsilon]
menangkap variabel seperti dengan [=], tetapi epsilon dengan referensiYang dihasilkan operator()
adalah const
secara default, dengan implikasi yang menangkap akan const
ketika Anda mengaksesnya secara default. Ini memiliki efek bahwa setiap panggilan dengan input yang sama akan menghasilkan hasil yang sama, namun Anda dapat menandai lambdamutable
untuk meminta bahwa operator()
yang dihasilkan tidak const
.
const
selalu ...
()
- dilewatkan sebagai lambda argumen-nol, tetapi karena () const
tidak cocok dengan lambda, itu mencari konversi tipe yang memungkinkannya, yang mencakup pemeran implisit -untuk-fungsi-pointer, dan kemudian menyebutnya! Sneaky!
std::function<double(int, bool)> f = [](int a, bool b) -> double { ... };
Tapi biasanya, kami membiarkan kompiler menyimpulkan jenis: auto f = [](int a, bool b) -> double { ... };
(dan jangan lupa #include <functional>
)
return d < 0.00001 ? 0 : d;
dijamin akan kembali dua kali lipat, ketika salah satu operan adalah konstanta bilangan bulat (itu karena aturan promosi implisit dari? konversi tidak peduli yang mana yang akan diambil). Mengubah ke 0.0 : d
mungkin akan membuat contoh lebih mudah dimengerti.
Konsep C ++ dari fungsi lambda berasal dari kalkulus lambda dan pemrograman fungsional. Lambda adalah fungsi tanpa nama yang berguna (dalam pemrograman aktual, bukan teori) untuk cuplikan kode pendek yang tidak mungkin untuk digunakan kembali dan tidak layak disebut.
Dalam C ++ fungsi lambda didefinisikan seperti ini
[]() { } // barebone lambda
atau dengan segala kemuliaan
[]() mutable -> T { } // T is the return type, still lacking throw()
[]
adalah daftar tangkap, ()
daftar argumen dan{}
fungsi tubuh.
Daftar penangkapan mendefinisikan apa dari luar lambda harus tersedia di dalam fungsi tubuh dan bagaimana. Itu bisa berupa:
Anda dapat mencampur salah satu di atas dalam daftar yang dipisahkan koma [x, &y]
.
Daftar argumen sama dengan fungsi C ++ lainnya.
Kode yang akan dieksekusi ketika lambda sebenarnya dipanggil.
Jika lambda hanya memiliki satu pernyataan pengembalian, jenis kembali dapat dihilangkan dan memiliki jenis implisit decltype(return_statement)
.
Jika lambda ditandai bisa berubah (mis []() mutable { }
) Itu diizinkan untuk mengubah nilai yang telah ditangkap oleh nilai.
Pustaka yang didefinisikan oleh standar ISO sangat diuntungkan oleh lambdas dan meningkatkan kegunaan beberapa bilah karena sekarang pengguna tidak perlu mengacaukan kode mereka dengan functors kecil dalam beberapa lingkup yang dapat diakses.
Dalam C ++ 14 lambdas telah diperpanjang oleh berbagai proposal.
Elemen daftar tangkapan sekarang dapat diinisialisasi dengan =
. Ini memungkinkan penggantian nama variabel dan untuk menangkap dengan memindahkan. Contoh yang diambil dari standar:
int x = 4;
auto y = [&r = x, x = x+1]()->int {
r += 2;
return x+2;
}(); // Updates ::x to 6, and initializes y to 7.
dan satu diambil dari Wikipedia yang menunjukkan cara menangkap dengan std::move
:
auto ptr = std::make_unique<int>(10); // See below for std::make_unique
auto lambda = [ptr = std::move(ptr)] {return *ptr;};
Lambdas sekarang bisa menjadi generik ( auto
akan setara dengan di T
sini jika
T
ada argumen tipe templat di suatu tempat di lingkup sekitarnya):
auto lambda = [](auto x, auto y) {return x + y;};
C ++ 14 memungkinkan tipe pengembalian yang disimpulkan untuk setiap fungsi dan tidak membatasi itu ke fungsi formulir return expression;
. Ini juga diperluas ke lambdas.
r = &x; r += 2;
tetapi ini terjadi pada nilai asli 4.
Ekspresi Lambda biasanya digunakan untuk merangkum algoritma sehingga mereka dapat diteruskan ke fungsi lain. Namun, dimungkinkan untuk mengeksekusi lambda segera setelah definisi :
[&](){ ...your code... }(); // immediately executed lambda expression
secara fungsional setara dengan
{ ...your code... } // simple code block
Ini membuat ekspresi lambda alat yang ampuh untuk refactoring fungsi kompleks . Anda mulai dengan membungkus bagian kode dalam fungsi lambda seperti yang ditunjukkan di atas. Proses parameterisasi eksplisit kemudian dapat dilakukan secara bertahap dengan pengujian lanjutan setelah setiap langkah. Setelah Anda memiliki kode-blok sepenuhnya parameter (seperti yang ditunjukkan oleh penghapusan&
), Anda dapat memindahkan kode ke lokasi eksternal dan menjadikannya fungsi normal.
Demikian pula, Anda dapat menggunakan ekspresi lambda untuk menginisialisasi variabel berdasarkan hasil algoritma ...
int a = []( int b ){ int r=1; while (b>0) r*=b--; return r; }(5); // 5!
Sebagai cara mempartisi logika program Anda, Anda bahkan mungkin merasa berguna untuk meneruskan ekspresi lambda sebagai argumen ke ekspresi lambda lain ...
[&]( std::function<void()> algorithm ) // wrapper section
{
...your wrapper code...
algorithm();
...your wrapper code...
}
([&]() // algorithm section
{
...your algorithm code...
});
Ekspresi Lambda juga memungkinkan Anda membuat fungsi bernama nested , yang bisa menjadi cara yang nyaman untuk menghindari duplikat logika. Menggunakan lambdas bernama juga cenderung sedikit lebih mudah pada mata (dibandingkan dengan lambdas inline anonim) ketika melewati fungsi non-sepele sebagai parameter ke fungsi lain. Catatan: jangan lupa titik koma setelah kurung kurawal tutup.
auto algorithm = [&]( double x, double m, double b ) -> double
{
return m*x+b;
};
int a=algorithm(1,2,3), b=algorithm(4,5,6);
Jika profiling berikutnya mengungkapkan overhead inisialisasi yang signifikan untuk objek fungsi, Anda dapat memilih untuk menulis ulang ini sebagai fungsi normal.
if
pernyataan :, if ([i]{ for (char j : i) if (!isspace(j)) return false ; return true ; }()) // i is all whitespace
dengan asumsi i
adalahstd::string
[](){}();
.
(lambda: None)()
Sintaksis Python jauh lebih mudah dibaca.
main() {{{{((([](){{}}())));}}}}
Jawaban
T: Apa yang dimaksud dengan ekspresi lambda di C ++ 11?
A: Di bawah tenda, itu adalah objek dari kelas yang di-autogenerasi dengan operator kelebihan beban () const . Objek semacam itu disebut penutupan dan dibuat oleh kompiler. Konsep 'closure' ini dekat dengan konsep bind dari C ++ 11. Tetapi lambdas biasanya menghasilkan kode yang lebih baik. Dan panggilan melalui penutupan memungkinkan inlining penuh.
T: Kapan saya akan menggunakannya?
A: Untuk mendefinisikan "logika sederhana dan kecil" dan meminta kompiler melakukan pembangkitan dari pertanyaan sebelumnya. Anda memberikan kompiler beberapa ekspresi yang Anda inginkan di dalam operator (). Semua kompiler hal-hal lain akan menghasilkan untuk Anda.
T: Kelas masalah apa yang mereka pecahkan yang tidak mungkin dilakukan sebelum perkenalan mereka?
A: Ini adalah semacam gula sintaksis seperti operator kelebihan beban alih-alih fungsi untuk penambahan kustom , operasi sub-transaksi ... Tapi itu menyimpan lebih banyak baris kode yang tidak dibutuhkan untuk membungkus 1-3 baris logika nyata ke beberapa kelas, dan lain-lain! Beberapa insinyur berpikir bahwa jika jumlah garis lebih kecil maka ada sedikit kesempatan untuk membuat kesalahan di dalamnya (saya juga berpikir demikian)
Contoh penggunaan
auto x = [=](int arg1){printf("%i", arg1); };
void(*f)(int) = x;
f(1);
x(1);
Ekstra tentang lambda, tidak tercakup oleh pertanyaan. Abaikan bagian ini jika Anda tidak tertarik
1. Nilai yang diambil. Apa yang bisa Anda ambil
1.1. Anda bisa merujuk ke variabel dengan durasi penyimpanan statis di lambdas. Mereka semua ditangkap.
1.2. Anda dapat menggunakan lambda untuk menangkap nilai "berdasarkan nilai". Dalam hal demikian vars yang ditangkap akan disalin ke objek fungsi (penutupan).
[captureVar1,captureVar2](int arg1){}
1.3. Anda dapat menangkap referensi menjadi. & - dalam konteks ini berarti referensi, bukan petunjuk.
[&captureVar1,&captureVar2](int arg1){}
1.4. Itu ada notasi untuk menangkap semua vars non-statis dengan nilai, atau dengan referensi
[=](int arg1){} // capture all not-static vars by value
[&](int arg1){} // capture all not-static vars by reference
1.5. Itu ada notasi untuk menangkap semua vars non-statis dengan nilai, atau dengan referensi dan tentukan lebih. Contoh: Tangkap semua vars bukan-statis dengan nilai, tetapi dengan menangkap referensi Param2
[=,&Param2](int arg1){}
Tangkap semua vars tidak-statis dengan referensi, tetapi dengan menangkap nilai Param2
[&,Param2](int arg1){}
2. Pengurangan jenis pengembalian
2.1. Jenis return Lambda dapat disimpulkan jika lambda adalah satu ekspresi. Atau Anda dapat menentukannya secara eksplisit.
[=](int arg1)->trailing_return_type{return trailing_return_type();}
Jika lambda memiliki lebih dari satu ekspresi, maka tipe kembali harus ditentukan melalui tipe trailing return. Juga, sintaksis serupa dapat diterapkan pada fungsi otomatis dan fungsi anggota
3. Nilai yang diambil. Apa yang tidak bisa Anda tangkap
3.1. Anda hanya dapat menangkap vars lokal, bukan variabel anggota objek.
4. konversi
4.1 !! Lambda bukan penunjuk fungsi dan bukan fungsi anonim, tetapi lambda tangkap-kurang dapat secara implisit dikonversi menjadi penunjuk fungsi.
ps
Lebih lanjut tentang informasi tata bahasa lambda dapat ditemukan dalam Draf Kerja untuk Bahasa Pemrograman C ++ # 337, 2012-01-16, 5.1.2. Ekspresi Lambda, hal.88
Di C ++ 14 fitur tambahan yang dinamai "init capture" telah ditambahkan. Hal ini memungkinkan untuk melakukan deklarasi anggota data penutupan secara militer:
auto toFloat = [](int value) { return float(value);};
auto interpolate = [min = toFloat(0), max = toFloat(255)](int value)->float { return (value - min) / (max - min);};
[&,=Param2](int arg1){}
Tampaknya ini bukan sintaks yang valid. Bentuk yang benar adalah[&,Param2](int arg1){}
Fungsi lambda adalah fungsi anonim yang Anda buat sebaris. Ini dapat menangkap variabel seperti yang telah dijelaskan oleh beberapa orang, (mis. Http://www.stroustrup.com/C++11FAQ.html#lambda ) tetapi ada beberapa batasan. Misalnya, jika ada antarmuka panggilan balik seperti ini,
void apply(void (*f)(int)) {
f(10);
f(20);
f(30);
}
Anda dapat menulis fungsi di tempat untuk menggunakannya seperti yang diteruskan untuk diterapkan di bawah:
int col=0;
void output() {
apply([](int data) {
cout << data << ((++col % 10) ? ' ' : '\n');
});
}
Tetapi Anda tidak bisa melakukan ini:
void output(int n) {
int col=0;
apply([&col,n](int data) {
cout << data << ((++col % 10) ? ' ' : '\n');
});
}
karena keterbatasan dalam standar C ++ 11. Jika Anda ingin menggunakan tangkapan, Anda harus bergantung pada perpustakaan dan
#include <functional>
(atau pustaka STL lainnya seperti algoritma untuk mendapatkannya secara tidak langsung) dan kemudian bekerja dengan fungsi std :: daripada meneruskan fungsi normal sebagai parameter seperti ini:
#include <functional>
void apply(std::function<void(int)> f) {
f(10);
f(20);
f(30);
}
void output(int width) {
int col;
apply([width,&col](int data) {
cout << data << ((++col % width) ? ' ' : '\n');
});
}
apply
templat yang menerima functor, itu akan berfungsi
Salah satu penjelasan terbaik lambda expression
diberikan oleh penulis C ++ Bjarne Stroustrup dalam bukunya ***The C++ Programming Language***
bab 11 ( ISBN-13: 978-0321563842 ):
What is a lambda expression?
Sebuah ekspresi lambda , kadang-kadang juga disebut sebagai lambda fungsi atau (ketat berbicara tidak benar, tapi bahasa sehari-hari) sebagai lambda , adalah notasi yang disederhanakan untuk mendefinisikan dan menggunakan objek fungsi anonim . Alih-alih mendefinisikan kelas bernama dengan operator (), kemudian membuat objek kelas itu, dan akhirnya memohonnya, kita bisa menggunakan singkatan.
When would I use one?
Ini sangat berguna ketika kita ingin meneruskan operasi sebagai argumen ke suatu algoritma. Dalam konteks antarmuka pengguna grafis (dan di tempat lain), operasi seperti itu sering disebut sebagai panggilan balik .
What class of problem do they solve that wasn't possible prior to their introduction?
Di sini saya kira setiap tindakan yang dilakukan dengan ekspresi lambda dapat diselesaikan tanpa mereka, tetapi dengan kode yang lebih banyak dan kompleksitas yang jauh lebih besar. Ekspresi Lambda ini adalah cara optimasi untuk kode Anda dan cara membuatnya lebih menarik. Sedih oleh Stroustup:
cara optimal untuk mengoptimalkan
Some examples
melalui ekspresi lambda
void print_modulo(const vector<int>& v, ostream& os, int m) // output v[i] to os if v[i]%m==0
{
for_each(begin(v),end(v),
[&os,m](int x) {
if (x%m==0) os << x << '\n';
});
}
atau melalui fungsi
class Modulo_print {
ostream& os; // members to hold the capture list int m;
public:
Modulo_print(ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{
if (x%m==0) os << x << '\n';
}
};
atau bahkan
void print_modulo(const vector<int>& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
class Modulo_print {
ostream& os; // members to hold the capture list
int m;
public:
Modulo_print (ostream& s, int mm) :os(s), m(mm) {}
void operator()(int x) const
{
if (x%m==0) os << x << '\n';
}
};
for_each(begin(v),end(v),Modulo_print{os,m});
}
jika kamu membutuhkannya kamu bisa memberi nama lambda expression
seperti di bawah ini:
void print_modulo(const vector<int>& v, ostream& os, int m)
// output v[i] to os if v[i]%m==0
{
auto Modulo_print = [&os,m] (int x) { if (x%m==0) os << x << '\n'; };
for_each(begin(v),end(v),Modulo_print);
}
Atau asumsikan sampel sederhana lain
void TestFunctions::simpleLambda() {
bool sensitive = true;
std::vector<int> v = std::vector<int>({1,33,3,4,5,6,7});
sort(v.begin(),v.end(),
[sensitive](int x, int y) {
printf("\n%i\n", x < y);
return sensitive ? x < y : abs(x) < abs(y);
});
printf("sorted");
for_each(v.begin(), v.end(),
[](int x) {
printf("x - %i;", x);
}
);
}
akan menghasilkan selanjutnya
0
1
0
1
0
1
0
1
0
1
0 diurutkanx - 1; x - 3; x - 4; x - 5; x - 6; x - 7; x - 33;
[]
- ini adalah daftar tangkap atau lambda introducer
: jikalambdas
tidak memerlukan akses ke lingkungan lokal mereka, kita dapat menggunakannya.
Kutipan dari buku:
Karakter pertama dari ekspresi lambda selalu [ . Seorang pengantar lambda dapat mengambil berbagai bentuk:
• [] : daftar tangkap kosong. Ini menyiratkan bahwa tidak ada nama lokal dari konteks sekitarnya dapat digunakan dalam tubuh lambda. Untuk ekspresi lambda seperti itu, data diperoleh dari argumen atau dari variabel nonlokal.
• [&] : secara implisit ditangkap dengan referensi. Semua nama lokal dapat digunakan. Semua variabel lokal diakses dengan referensi.
• [=] : secara implisit ditangkap oleh nilai. Semua nama lokal dapat digunakan. Semua nama merujuk pada salinan variabel lokal yang diambil pada titik panggilan ekspresi lambda.
• [daftar tangkap]: penangkapan eksplisit; daftar tangkap adalah daftar nama variabel lokal yang akan ditangkap (yaitu, disimpan dalam objek) dengan referensi atau dengan nilai. Variabel dengan nama yang didahului oleh & ditangkap oleh referensi. Variabel lain ditangkap oleh nilai. Daftar tangkap juga dapat berisi ini dan nama diikuti oleh ... sebagai elemen.
• [&, daftar tangkap] : tangkap secara tersirat dengan merujuk semua variabel lokal dengan nama yang tidak disebutkan dalam daftar. Daftar tangkap dapat berisi ini. Nama yang terdaftar tidak dapat didahului oleh &. Variabel yang disebutkan dalam daftar tangkap ditangkap oleh nilai.
• [=, daftar tangkap] : tangkap secara implisit dengan nilai semua variabel lokal dengan nama yang tidak disebutkan dalam daftar. Daftar tangkap tidak dapat mengandung ini. Nama yang terdaftar harus didahului oleh &. Variabel yang disebutkan dalam daftar tangkap ditangkap oleh referensi.
Perhatikan bahwa nama lokal yang didahului oleh & selalu ditangkap oleh referensi dan nama lokal yang tidak diawali oleh & selalu ditangkap oleh nilai. Hanya menangkap dengan referensi yang memungkinkan modifikasi variabel dalam lingkungan panggilan.
Additional
Lambda expression
format
Referensi tambahan:
for (int x : v) { if (x % m == 0) os << x << '\n';}
Nah, salah satu penggunaan praktis yang saya temukan adalah mengurangi kode pelat boiler. Sebagai contoh:
void process_z_vec(vector<int>& vec)
{
auto print_2d = [](const vector<int>& board, int bsize)
{
for(int i = 0; i<bsize; i++)
{
for(int j=0; j<bsize; j++)
{
cout << board[bsize*i+j] << " ";
}
cout << "\n";
}
};
// Do sth with the vec.
print_2d(vec,x_size);
// Do sth else with the vec.
print_2d(vec,y_size);
//...
}
Tanpa lambda, Anda mungkin perlu melakukan sesuatu untuk bsize
kasus yang berbeda . Tentu saja Anda bisa membuat fungsi tetapi bagaimana jika Anda ingin membatasi penggunaan dalam lingkup fungsi pengguna jiwa? sifat lambda memenuhi persyaratan ini dan saya menggunakannya untuk kasus itu.
Lambda di c ++ diperlakukan sebagai "fungsi yang tersedia". ya itu benar-benar sedang bepergian, Anda mendefinisikannya; Gunakan; dan saat ruang lingkup fungsi induk selesai, fungsi lambda hilang.
c ++ memperkenalkannya di c ++ 11 dan semua orang mulai menggunakannya seperti di setiap tempat yang memungkinkan. contoh dan apa itu lambda dapat ditemukan di sini https://en.cppreference.com/w/cpp/language/lambda
saya akan menjelaskan yang tidak ada tetapi penting untuk diketahui untuk setiap programmer c ++
Lambda tidak dimaksudkan untuk digunakan di mana-mana dan setiap fungsi tidak dapat diganti dengan lambda. Ini juga bukan yang tercepat dibandingkan dengan fungsi normal. karena memiliki beberapa overhead yang perlu ditangani oleh lambda.
itu pasti akan membantu mengurangi jumlah garis dalam beberapa kasus. itu pada dasarnya dapat digunakan untuk bagian kode, yang dipanggil dalam fungsi yang sama satu kali atau lebih dan potongan kode itu tidak diperlukan di tempat lain sehingga Anda dapat membuat fungsi mandiri untuk itu.
Di bawah ini adalah contoh dasar lambda dan apa yang terjadi di latar belakang.
Kode pengguna:
int main()
{
// Lambda & auto
int member=10;
auto endGame = [=](int a, int b){ return a+b+member;};
endGame(4,5);
return 0;
}
Bagaimana kompilasi mengembangkannya:
int main()
{
int member = 10;
class __lambda_6_18
{
int member;
public:
inline /*constexpr */ int operator()(int a, int b) const
{
return a + b + member;
}
public: __lambda_6_18(int _member)
: member{_member}
{}
};
__lambda_6_18 endGame = __lambda_6_18{member};
endGame.operator()(4, 5);
return 0;
}
jadi seperti yang Anda lihat, jenis overhead apa yang ditambahkan ketika Anda menggunakannya. jadi itu bukan ide yang baik untuk menggunakannya di mana-mana. itu dapat digunakan di tempat-tempat di mana mereka berlaku.
Satu masalah yang dipecahkannya: Kode lebih sederhana daripada lambda untuk panggilan dalam konstruktor yang menggunakan fungsi parameter output untuk menginisialisasi anggota const
Anda dapat menginisialisasi anggota const kelas Anda, dengan panggilan ke fungsi yang menetapkan nilainya dengan mengembalikan output sebagai parameter output.