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 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:
#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
SomeCompilerGeneratedTypeName1danSomeCompilerGeneratedTypeName2
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 autoseharusnya:
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