Lambda adalah fungsi anonim (fungsi tanpa nama) yang dapat didefinisikan dan digunakan secara inline di C++. Mereka menyediakan cara mudah untuk meneruskan potongan kecil kode sebagai argumen ke fungsi lain, atau untuk mendefinisikan suatu fungsi tanpa harus membuat fungsi bernama.

Lambdas menyediakan cara yang fleksibel dan ringkas untuk menulis objek mirip fungsi di C++, dan banyak digunakan dalam pemrograman C++ modern.

Lambdas didefinisikan menggunakan sintaks berikut:

[ capture list ] ( argument list ) -> return type { function body }
  • capture list digunakan untuk menentukan variabel dari lingkup sekitar yang dapat diakses dalam lambda. Variabel dapat ditangkap berdasarkan nilai, referensi, atau menggunakan this.
  • argument listmenentukan parameter yang akan diteruskan ke lambda.
  • return type menentukan jenis nilai yang akan dikembalikan lambda. Jika tidak ditentukan, kompiler akan mencoba menyimpulkannya.
  • function body menentukan kode yang akan dieksekusi ketika lambda dipanggil.

Berikut adalah beberapa cara berbeda untuk menggunakan lambda di C++:

  1. Panggilan Balik Fungsi
  2. Menangkap default
  3. Menangkap berdasarkan nilai
  4. Menangkap dengan referensi
  5. Lambda yang bisa berubah

{1} Callback Fungsi

Callback fungsi adalah fungsi yang diteruskan sebagai argumen ke fungsi lain dan dipanggil oleh fungsi penerima di lain waktu. Anda dapat meneruskan lambda sebagai argumen fungsi, yang akan dieksekusi ketika peristiwa tertentu terjadi.

Contoh:

#include <iostream>
#include <algorithm>
#include <vector>

int main() {
  std::vector<int> numbers = {1, 2, 3, 4, 5};

  // Lambda expression to find the sum of two numbers
  auto sum = [](int a, int b) { return a + b; };

  int result = std::accumulate(numbers.begin(), numbers.end(), 0, sum);
  std::cout << "Sum of elements in the vector: " << result << std::endl;

  return 0;
}

Dalam contoh ini, variabel sum adalah ekspresi Lambda yang mengambil dua parameter a dan b dan mengembalikan jumlahnya. Fungsi std::accumulate mengambil vektor bilangan, nilai awal hasil, dan fungsi penjumlahan (ekspresi Lambda). Fungsi ini menghitung jumlah semua elemen dalam vektor dan mengembalikan hasilnya, yang dicetak di layar.

Contoh lain:

#include <iostream>
#include <algorithm>
#include <vector>

int main()
{
    std::vector<int> vec = { 1, 2, 3, 4, 5 };
    int sum = 0;
    std::for_each(vec.begin(), vec.end(), [&sum](int x) { sum += x; });
    std::cout << "The sum is: " << sum << std::endl;
    return 0;
}

Dalam hal ini, ekspresi lambda [&sum](int x) { sum += x; } diteruskan sebagai fungsi yang akan diterapkan ke setiap elemen. Lambda menangkap variabel sum dengan referensi & sehingga dapat dimodifikasi di dalam badan lambda.

Kedua contoh mencapai hasil yang sama, namun contoh kedua menggunakan algoritma std::for_each dan ekspresi lambda, yang merupakan teknik yang lebih modern dan ringkas dalam C++.

{2} Menangkap default

Ketika ekspresi lambda dideklarasikan tanpa tangkapan eksplisit apa pun, perilaku defaultnya adalah menangkap variabel dalam cakupan sekitarnya dengan referensi. Ini disebut sebagai pengambilan default.

Contoh:

#include <iostream>

int main() {
  int x = 42;
  auto f = [ ]() { std::cout << x << std::endl; };
  f();
  return 0;
}
#include <iostream>

int main()
{
    auto square = [](int x) { return x * x; };
    std::cout << "The square of 5 is: " << square(5) << std::endl;
    return 0;
}

Pada contoh kedua, ekspresi lambda didefinisikan dan disimpan dalam variabel bernama square. Ekspresi lambda ini mengambil argumen int x dan mengembalikan nilai x * x, yang merupakan kuadrat dari argumen tersebut.

Dalam fungsi main, ekspresi lambda ini digunakan sebagai objek fungsi. Dipanggil dengan meneruskan argumen 5 dan hasilnya ditampilkan menggunakan aliran cout.

{3} Menangkap berdasarkan nilai

Ini adalah bentuk ekspresi lambda yang paling sederhana, di mana Anda meneruskan variabel ke fungsi berdasarkan nilai. Ketika suatu variabel ditangkap berdasarkan nilai, nilainya saat ini disimpan dalam penutupan dan tidak diperbarui ketika variabel berubah dalam lingkup sekitarnya. Hal ini dilakukan dengan memasukkan variabel dalam tanda kurung siku [ ]

Contoh

#include <iostream>

int main() {
  int x = 42;
  auto f = [x]() { std::cout << x << std::endl; };
  f();
  return 0;
}
#include <iostream>

int main() {
    int x = 42;
    auto f = [x](int y) { std::cout << x+y << std::endl;};
    f(1);
    return 0;
}

{4} Menangkap dengan referensi

Anda dapat meneruskan variabel ke ekspresi lambda dengan referensi menggunakan simbol &. Ketika suatu variabel ditangkap dengan referensi, nilainya saat ini disimpan dalam penutupan dan diperbarui ketika variabel berubah dalam lingkup sekitarnya. Hal ini dilakukan dengan mencantumkan alamat operator & di depan variabel dalam tanda kurung siku [ ].

Contoh

#include <iostream>

int main() {
  int x = 42;
  auto f = [&x]() { std::cout << x << std::endl; };
  f();
  return 0;
}
#include <iostream>

int main() {
  int x = 10;

  auto add_one = [&x]() { ++x; };
  add_one();
  std::cout << x << "\n";

  return 0;
}
#include <iostream>

int main() {
  int x = 42;
  auto f = [&x]() { std::cout << x << std::endl; };
  f();
  return 0;
}

Dalam contoh terakhir, variabel x ditangkap dengan referensi, dan lambda add dapat mengubah nilainya.

{5} Lambda yang Dapat Diubah

Secara default, variabel yang ditangkap oleh ekspresi lambda bersifat konstan dan tidak dapat diubah di dalam isi ekspresi lambda. Jika Anda ingin mengubah variabel yang diambil dalam ekspresi lambda, Anda dapat membuat ekspresi lambda bisa berubah. Lambda yang dapat diubah memungkinkan variabel yang diambil untuk dimodifikasi. Hal ini dilakukan dengan memasukkan kata kunci mutable dalam tanda kurung siku [ ].

Contoh

#include <iostream>

int main() {
  int x = 42;
  auto f = [x]() mutable { std::cout << ++x << std::endl; };
  f();
  return 0;
}

{Kesimpulan}

Ekspresi lambda mirip dengan fungsi biasa, namun memiliki beberapa perbedaan utama. Misalnya, tipe ekspresi lambda tidak ditentukan secara eksplisit, namun dapat disimpulkan oleh kompiler. Selain itu, ekspresi lambda dapat menangkap variabel dari lingkup sekitarnya, menjadikannya sangat berguna untuk membuat penutupan dan bekerja dengan konsep pemrograman fungsional di C++.

Lambdas memiliki beberapa keunggulan kinerja dibandingkan fungsi tradisional

  1. Fungsi Inline: Lambda secara otomatis disisipkan oleh kompiler, yang berarti bahwa kodenya langsung dimasukkan ke dalam fungsi pemanggil. Hal ini dapat mengurangi overhead pemanggilan fungsi dan meningkatkan kinerja.
  2. Menghindari Overhead pada Fungsi yang Dinamakan: Lambdas tidak memiliki nama, sehingga tidak harus dideklarasikan dan disimpan dalam tabel simbol, sehingga dapat mengurangi overhead dan meningkatkan kinerja.
  3. Peningkatan Lokalitas Cache: Lambda dapat didefinisikan dan digunakan dalam fungsi yang sama, yang berarti bahwa kode dan data yang digunakan oleh lambda akan disimpan dalam baris cache yang sama dengan kode pemanggil. Hal ini dapat meningkatkan lokalitas cache dan mengurangi biaya kesalahan cache.
  4. Mengurangi Ukuran Kode: Lambda biasanya lebih kecil dari fungsi bernama, dan tidak memerlukan pemanggilan fungsi eksternal, yang dapat mengurangi ukuran kode yang dikompilasi dan meningkatkan kinerja.
  5. Peningkatan Fleksibilitas: Lambdas dapat digunakan untuk meneruskan fungsi sebagai argumen ke fungsi lain, yang memberikan fleksibilitas lebih besar dalam cara kode dapat digunakan kembali dan diatur. Hal ini dapat meningkatkan kinerja dengan mengurangi kebutuhan akan kode duplikat.
  6. Peningkatan Keterbacaan: Lambdas dapat membuat kode lebih mudah dibaca dengan merangkum logika kompleks dalam cara yang ringkas dan mandiri. Hal ini dapat meningkatkan kinerja dengan mempermudah pemahaman dan pemeliharaan kode.

Singkatnya, lambda dapat memberikan peningkatan kinerja dibandingkan fungsi tradisional dengan mengurangi overhead, meningkatkan lokalitas cache, mengurangi ukuran kode, meningkatkan fleksibilitas, dan meningkatkan keterbacaan.

Terbaik