C++20 리서치 - 람다의 변화[2]
C++20 에서 추가된 람다 표현식의 특징은 다음과 같습니다.
- 템플릿 사용 가능
- 평가 되지 않은 표현식 사용 가능
- 캡쳐 하지 않은 표현식에서 디폴트 생성자와 대입 연산자 사용 가능
- 암시적 this 캡쳐 deprecated
- parameter pack 캡쳐 가능
람다 표현식 템플릿
-
기존에 람다 표현식 입력 인자를 auto로 할 경우 C++14 부터 자동으로 템플릿화 하여 여러 타입에 대응되는 표현식을 작성 할 수 있으나, 동일 타입에 대해서만 동작하게 만들 수 없었습니다.
-
C++20 방식 예제
auto add = [](auto a, auto b) {return a+b;} // C++14 모든 타입 대응가능 auto add = [](auto a, decltype(a) b) {return a+b;} // C++14 a와 b 타입 동일시 하지만, 원치 않은 동작 발생 가능 auto add = []<typename T>(T a, T b) {return a+b;} // C++20 새로운 방식, 타입이 다를 경우 컴파일 오류 발생
평가 되지 않은 표현식
-
런타임 시간에는 실행되지 않고, 컴파일 시간에만 사용 되는 표현식 sizoeof, decltype, typeid, nocept
-
C++17까지는 람다 표현식을 평가되지 않은 표현식으로 사용 할 수 없었음, But 20부터 가능해졌습니다.
std::cout << sizeof( [](int a, int b) { return a+b; } ) << std::endl; // C++17 불가, C++20 허용 // 활용 : 스마트 포인터 deleter의 인자로 람다를 넘겨 줄 수 있음 C++20 std::unique_ptr<int, decltype( [](int* p) { delete p; })> pVal( new int );
람다 표현식과 디폴트 생성자
// 캡쳐 없는 케이스
int v = 10;
auto r1 = [](int a, int b) {return a + b};
// ~C++17 C++20
decltype(r1) r2; // 불가 가능
decltype(r1) r3 = r1; // 가능 가능
r3 = r1; // 불가 가능
// 캡쳐 있는 케이스
int v = 10;
auto r1 = [v](int a, int b) {return a + b};
// ~C++17 C++20
decltype(r1) r2; // 불가 !!불가!!
decltype(r1) r3 = r1; // 가능 가능
r3 = r1; // 불가 !!불가!!
암묵적 this 캡쳐 deprecated
- 기존 람다 표현식 캡쳐시 [=] 할 경우 [=, this]와 같은 의미였습니다. [=]로 캡쳐시 표현식 안에서 지역변수와 모든 멤버 변수에 접근이 가능합니다. 하지만 객체 수명 주기로 인해 의도치 않은 버그를 만들어 낼 수 있습니다. (잡기 힘든 버그가 됨. 매우 위험)
- C++ 20 부터는 [=] 로 캡쳐시 컴파일로 경고가 발생 합니다.( 암묵적 this 캡쳐 사용은 좋지 않은 방법이고. 명시적인 값복사 사용을 권장합니다. )
Parameter pack 캡쳐( C++17 이전에는 캡쳐 불가 )
// 값 캡쳐
template<typename ... Args> auto name(Args&&... args)
{
return [...args = std::forward<args)](){ std::cout << ... << args); };
}
// 참조 캡쳐
template<typename ... Args> auto name(Args&&... args)
{
return [&...args = std::forward<args)](){ std::cout << ... << args); };
}