Ответы:
Отдельные лямбды переводятся компилятором в разные классы. Например, определение 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