Jawaban:
Lambda individu diterjemahkan ke kelas yang berbeda oleh kompiler. Misalnya, definisi lambda1 setara dengan:
class SomeCompilerGeneratedTypeName {
public:
SomeCompilerGeneratedTypeName(...) { // Capture all the required variables here
}
void operator()(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 typeid
operator. 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:
#include <iostream>
#include <typeinfo>
int main()
{
struct T {
};
auto lambda1 = [&](T& arg) {
return;
};
auto lambda2 = [&](T& arg) {
return;
};
std::cout << typeid(lambda1).name() << "/" << typeid(lambda1).hash_code() << std::endl;
std::cout << typeid(lambda2).name() << "/" << typeid(lambda2).hash_code() << std::endl;
return 0;
}
Output dari program ini adalah (dengan GCC 8.3, lihat di Gobolt ):
Z4mainEUlRZ4mainE1TE_/7654536205164302515
Z4mainEUlRZ4mainE1TE0_/10614161759544824066
SomeCompilerGeneratedTypeName1
danSomeCompilerGeneratedTypeName2
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.
Kompiler tidak dapat memutuskan jenis apa yang auto
seharusnya:
auto lambda = condition ? lambda1 : lambda2;
karena setiap lambda memiliki tipe yang berbeda dan unik.
Salah satu cara yang akan berhasil adalah:
auto lambda = [&](T& arg) {
return (condition ? lambda1(arg) : lambda2(arg));
}
Itu tidak dikompilasi karena setiap lambda memiliki tipe yang unik, tidak ada tipe yang umum untuk ?:
.
Anda bisa membungkusnya std::function<void(T&)>
, misalnya
auto lamba1 = [&](T& arg) {
...
};
auto lambda2 = [&](T& arg) {
...
};
auto lambda = condition ? std::function(lambda1) : lambda2; // C++17 class template deduction