Lambda individu diterjemahkan ke kelas yang berbeda oleh kompiler. Misalnya, definisi lambda1 setara dengan:
classSomeCompilerGeneratedTypeName{public:SomeCompilerGeneratedTypeName(...){// Capture all the required variables here}voidoperator()(T& arg)const{// ...}private:// All the captured variables here ...};
Oleh karena itu, dua jenis berbeda dihasilkan oleh kompiler, yang menyebabkan ketidakcocokan jenis auto lambda = condition ? lambda1 : lambda2;
Berikut ini akan berfungsi:
auto lambda = condition ? std::function<void(T&)>(lambda1): std::function<void(T&)>(lambda2);
Untuk menyoroti bahwa kedua lambda memang jenis yang berbeda, kita dapat menggunakan <typeinfo>dari perpustakaan standar dan typeidoperator. Lambdas bukan tipe polimorfik, sehingga standar menjamin bahwa operator 'typeid' dievaluasi pada waktu kompilasi. Ini menunjukkan bahwa contoh berikut ini valid bahkan jika RTTI dinonaktifkan:
Kesalahan lengkap adalah "error: operan to?: Memiliki tipe f yang berbeda (const std :: vector <int> &, size_t, size_t) [dengan T = char yang tidak ditandatangani; size_t = int unsigned yang lama] :: <lambda (unsigned char & )> 'dan' f (const std :: vector <int> &, size_t, size_t) [dengan T = char unsigned; size_t = int unsigned lama] :: <lambda (unsigned char &)> '", di mana saya melihat identik semua jenis & format.
sapi
1
@cow Karena lambda dalam dirinya sendiri memiliki tanda tangan yang sama sehingga kompiler, untuk menyembunyikan detail implementasi dan untuk memberikan kesalahan yang lebih dimengerti, memberi Anda lokasi dan tanda tangan dari kedua lambda yang identik. Namun pada akhirnya, mereka masih ditafsirkan sebagai SomeCompilerGeneratedTypeName1danSomeCompilerGeneratedTypeName2
Xatyrian
1
@cow saya menambahkan contoh yang menyoroti awal jawaban, Anda mungkin menemukan itu menarik
Xatyrian
12
Anehnya, jika lambdas tidak menangkap, +trik operator dapat digunakan:
auto lambda1 =[](int arg){...};auto lambda2 =[](int arg){...};auto lambda = condition ?+lambda1 :+lambda2;// This compiles!
lambda(2019);
Ini berfungsi, karena +akan mengubah lambda menjadi pointer fungsi, dan kedua pointer fungsi memiliki tipe yang sama (seperti void (*)(int)).
Dengan GCC dan Dentang (tetapi tidak dengan MSVC), +dapat dihilangkan, lambdas masih akan dikonversi menjadi pointer fungsi.
Karena 2 lambda ( lambda1dan lambda2) adalah 2 jenis yang berbeda,?: tidak dapat menyimpulkan jenis pengembalian untuk lambdadari lambda1dan lambda2. Ini terjadi karena 2 ini tidak dapat dikonversi satu sama lain.
SomeCompilerGeneratedTypeName1
danSomeCompilerGeneratedTypeName2
Anehnya, jika lambdas tidak menangkap,
+
trik operator dapat digunakan:Ini berfungsi, karena
+
akan mengubah lambda menjadi pointer fungsi, dan kedua pointer fungsi memiliki tipe yang sama (sepertivoid (*)(int)
).Dengan GCC dan Dentang (tetapi tidak dengan MSVC),
+
dapat dihilangkan, lambdas masih akan dikonversi menjadi pointer fungsi.sumber
Kompiler tidak dapat memutuskan jenis apa yang
auto
seharusnya:karena setiap lambda memiliki tipe yang berbeda dan unik.
Salah satu cara yang akan berhasil adalah:
sumber
Itu tidak dikompilasi karena setiap lambda memiliki tipe yang unik, tidak ada tipe yang umum untuk
?:
.Anda bisa membungkusnya
std::function<void(T&)>
, misalnyasumber
Karena 2 lambda (
lambda1
danlambda2
) adalah 2 jenis yang berbeda,?:
tidak dapat menyimpulkan jenis pengembalian untuklambda
darilambda1
danlambda2
. Ini terjadi karena 2 ini tidak dapat dikonversi satu sama lain.sumber