Lambda Expression (람다 표현식)

개념

  • 익명의 함수 객체 생성하는 문법.
  • 캡처 기능으로 지역 변수를 바인딩 가능.
  • inline 혹은 constexpr

기본 문법

  auto add = [](int a, int b) { return a + b; };
  

캡처 방식

  • [v1]: 값 캡처
  • [&v1]: 참조 캡처
  • [=]: 모든 외부 변수를 값 캡처
  • [&]: 모든 외부 변수를 참조 캡처

Lambda Expression의 원리

  • “Closure"를 만드는 표현식
  • 컴파일러 동작
    • 람다를 보고 그에 상응하는 함수 객체를 컴파일러가 제작
    • 람다 함수 자리가 Closure Object가 됨
    • Closure Object
      • lambda expression이 만드는 unnamed function object

mutable lambda

  • 기본적으로 operator()const → **mutable**을 사용하면 non-const 가능.
  • 참고로 레퍼런스를 캡쳐한 경우 어차피 레퍼런스가 아닌 레퍼런스가 가리키는 곳의 값을 바꾸는 것이라 mutable 쓰나 안쓰나 상관없음.
  auto f = [v1](int a) mutable { v1 = a; };
  

Lambda의 타입과 함수 포인터 변환

  • 모든 람다고유한 타입.
  • 캡처 없는 람다는 함수 포인터로 변환 가능.
    • 원리
      • operator()와 동일한 기능을 수행하는 static member function 생성
      • 변환 생성자 제공

람다 저장 방식

  • auto: 오버헤드 없음, 인라인 치환 가능.
  • 함수 포인터: 오버헤드 약간, 인라인 어려움.
  • std::function<>: 오버헤드 있음, 다양한 호출 가능.
    •   std::function<int(int, int)> f3 = [](inta, int b) { return a + b; }
        

상황별 판단

  • 한 개의 lambda expression을 사용할 경우 auto가 유리
  • 계속 담을 것을 바꾸는 유연성 측면에선 함수 포인터나 std::function 유리
  • 그러나 함수 포인터는 캡처하면 못 담고, functional의 plus같은 변환을 지원하지않는 객체는 못 담음

람다 표현식과 단위 전략

  • C++버전별 차이
    • 17
      • 람다 표현식은 unevaluated context에서 사용될 수 없고 디폴트 생성자가 없다
    • 20
      • 람다 표현식은 unevaluated context에서 사용될 수 있고 캡처하지 않은 람다표현식은 디폴트 생성자가 있다
  • sizeof, decltype
      // C++ 20
    int s1 = sizeof([](int a, int b){ return a + b; })
    using T1 = decltype([](int a, int b){ return a + b; })
    
    // C++ 11
    auto lambda = [](int a, int b){ return a + b; }
    int s2 = sizeof(lambda);
    usint T2 = decltype(lambda);
      

Generic & Template Lambda Expressoin

Generic Lambda (C++14)

  • 개념
    • 람다의 인자를 auto로 적는 것
  • 원리
    • operator() 함수를 템플릿으로 제공하는 것
  auto add = [](auto a, auto b) { return a + b; };
  
  • 일반 함수 auto (C++20)
    • 원리는 동일
      auto add(auto a, auto b)
      

Template Lambda (C++20)

  auto swap = []<typename T>(T& a, T& b) { auto tmp = a; a = b; b = tmp; };
  
  • Generic Lambda: 타입을 자유롭게 받음.
  • Template Lambda: 타입 제약 가능 (예: 같은 타입만).