Відповіді:
Окремі лямбди перекладачем перекладаються в різні класи. Наприклад, визначення lambda1 еквівалентно:
class SomeCompilerGeneratedTypeName {
public:
SomeCompilerGeneratedTypeName(...) { // Capture all the required variables here
}
void operator()(T& arg) const {
// ...
}
private:
// All the captured variables here ...
};
Тому компілятор генерує два різні типи, що викликає несумісність типу для auto lambda = condition ? lambda1 : lambda2;
Працює таке:
auto lambda = condition ? std::function<void(T&)>(lambda1) : std::function<void(T&)>(lambda2);
Щоб підкреслити, що обидва лямбда - це дійсно різні типи, ми можемо використовувати <typeinfo>
зі стандартної бібліотеки та typeid
оператора. Лямбди не є поліморфними типами, тому стандарт гарантує, що оператор 'typeid' оцінюється під час компіляції. Це показує, що наступний приклад дійсний, навіть якщо RTTI вимкнено:
#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;
}
Вихід програми (з GCC 8.3, див. На Gobolt ):
Z4mainEUlRZ4mainE1TE_/7654536205164302515
Z4mainEUlRZ4mainE1TE0_/10614161759544824066
SomeCompilerGeneratedTypeName1
іSomeCompilerGeneratedTypeName2
Цікаво, що якщо лямбдас не захоплює, +
може бути використана хитрість оператора :
auto lambda1 = [](int arg) { ... };
auto lambda2 = [](int arg) { ... };
auto lambda = condition ? +lambda1 : +lambda2; // This compiles!
lambda(2019);
Це працює, тому що +
перетворить лямбда в функціональний покажчик, і обидва функціональні вказівники мають один і той же тип (щось подібне void (*)(int)
).
Якщо GCC та Clang (але не з MSVC) +
можуть бути опущені, лямбдати все одно перетворяться на функціональні покажчики.
Він не компілюється, оскільки кожна лямбда має унікальний тип, для неї не існує загального типу ?:
.
Ви можете їх загорнути std::function<void(T&)>
, наприклад
auto lamba1 = [&](T& arg) {
...
};
auto lambda2 = [&](T& arg) {
...
};
auto lambda = condition ? std::function(lambda1) : lambda2; // C++17 class template deduction