답변:
컴파일러는 개별 람다를 다른 클래스로 변환합니다. 예를 들어 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 제외)에서는 +
생략 할 수 있지만 람다는 여전히 함수 포인터로 변환됩니다.