Apa perlunya template lambda yang diperkenalkan di C ++ 20 ketika C ++ 14 sudah memiliki lambda generik?

99

memperkenalkan lambda generik yang memungkinkan untuk menulis sebagai berikut:

auto func = [](auto a, auto b){
    return a + b;
};
auto Foo = func(2, 5);
auto Bar = func("hello", "world");

Sangat jelas bahwa lambda generik ini funcbekerja seperti fungsi templated yang funcakan bekerja.

Mengapa komite C ++ memutuskan untuk menambahkan sintaks template untuk lamda generik?

coder3101
sumber
5
Bagaimana jika Anda perlu menggunakan tipe templat yang berbeda dari untuk argumen atau tipe kembalian? Dan bagaimana jika itu dibutuhkan di dalam tubuh?
Beberapa programmer dude
Saya telah diberitahu bahwa ini adalah kasus penggunaan yang menarik.
Max Langhof
Lihat ini untuk perbandingan versi lambda yang berbeda: modernescpp.com/index.php/more-powerful-lambdas-with-c-20
schoetbi

Jawaban:

115

Lambda generik C ++ 14 adalah cara yang sangat keren untuk menghasilkan functor dengan operator ()tampilan seperti ini:

template <class T, class U>
auto operator()(T t, U u) const;

Tapi tidak seperti ini:

template <class T>
auto operator()(T t1, T t2) const; // Same type please

Juga tidak seperti ini:

template <class T, std::size_t N>
auto operator()(std::array<T, N> const &) const; // Only `std::array` please

Juga tidak seperti ini (meskipun ini agak sulit untuk benar-benar digunakan):

template <class T>
auto operator()() const; // No deduction

C ++ 14 lambda baik-baik saja, tetapi C ++ 20 memungkinkan kita mengimplementasikan kasus ini tanpa kerumitan.

Quentin
sumber
2
Bagus dan ringkas. Hanya menambahkan ini: Yang pertama (tipe yang sama) dapat diselesaikan dengan (auto a, decltype(a) b)C ++ 14.
Sebastian Mach
13
@Sebastianach hampir. Dengan solusi bitu tidak terdeduksi, dan argumennya akan secara implisit diubah menjadi tipe asebagai gantinya.
Quentin
32

Karena Anda dapat menggunakan lambda kerangka di C ++ 20, Anda dapat membatasi tipe Anda dengan cara yang lebih mudah daripada ekspresi SFINAE:

auto lambda = []<typename T>(std::vector<T> t){};

Lambda ini hanya akan bekerja dengan jenis vektor.

Antoine Morrier
sumber
8
Bagaimana constevalterkait dengan sintaks baru? Itu keren dan semuanya, tapi saya tidak mengerti relevansinya.
StoryTeller - Unslander Monica
Ini lebih merupakan informasi tentang apa yang ditambahkan C ++ 20 ke ekspresi lambda daripada jawaban atas pertanyaan
Antoine Morrier
24

The Proposal yang diterima ke C ++ 20 memiliki bagian motivasi yang panjang, dengan contoh-contoh. Premisnya adalah ini:

Ada beberapa alasan utama mengapa sintaks saat ini untuk mendefinisikan lambda generik dianggap tidak memadai oleh penulis. Intinya adalah bahwa beberapa hal yang dapat dilakukan dengan mudah dengan templat fungsi normal memerlukan lompatan lingkaran yang signifikan untuk dilakukan dengan lambda generik, atau tidak dapat dilakukan sama sekali. Penulis berpikir bahwa lambda cukup berharga sehingga C ++ harus mendukungnya sama seperti template fungsi normal.

Berikut ini adalah beberapa contoh.

StoryTeller - Unslander Monica
sumber
21

"Sintaks template familiar" baru untuk lambda yang diperkenalkan di C ++ 20 membuat konstruksi seperti  for_types dan  for_range layak serta jauh lebih mudah dibaca dibandingkan dengan alternatif C ++ 17.

(sumber: iterasi waktu kompilasi dengan C ++ 20 lambda )

Hal menarik lainnya yang dapat dilakukan pada lambda generik C ++ 14 dan C ++ 17 adalah secara langsung memanggil  operator() dengan meneruskan parameter template secara eksplisit:

C ++ 14:

   auto l = [](auto){ };
   l.template operator()<int>(0);

C ++ 20:

  auto l = []<typename T>(){ };
  l.template operator()<int>();

Contoh C ++ 14 di atas cukup tidak berguna: tidak ada cara untuk merujuk ke tipe yang disediakan  operator() di dalam tubuh lambda tanpa memberi nama dan menggunakan argumen  decltype. Selain itu, kami terpaksa memberikan argumen meskipun kami mungkin tidak membutuhkannya.

Contoh C ++ 20 menunjukkan bagaimana T mudah diakses dalam isi lambda dan bahwa lambda nullary sekarang dapat dibuatkan template secara sewenang-wenang. Ini akan sangat berguna untuk implementasi konstruksi waktu kompilasi yang disebutkan sebelumnya

Hamza.S
sumber