본문 바로가기
C++/C++14

C++14 : 람다 캡처 표현식(Lambda capture expressions)

by 개발자J의일상 2022. 4. 28.
반응형

C++11 람다 함수는 값 복사 또는 참조로 외부 범위에서 선언된 변수를 캡처한다.

이는 람다의 값 멤버가 이동 전용 타입이 될 수 없음을 의미한다.

C++14에서는 캡처된 멤버를 임의의 표현식으로 초기화할 수 있다.

이를 통해 외부 범위에 해당하는 명명된 변수를 갖지 않고도 값 이동에 의한 캡처와 람다의 임의 멤버 선언을 모두 수행할 수 있다.

 

이것은 이니셜라이저 표현식을 사용하여 수행됩니다.

auto lambda = [value = 1] {return value;};

람다 함수 lambda는 초기화한 값인 1을 반환한다. 선언된 캡처는 자동으로 이니셜라이저 표현식에서 타입을 추론한다.

 

이것은 표준 std::move 함수를 사용하여 이동으로 캡처하는 데 사용할 수 있다.

std::unique_ptr<int> ptr(new int(10));
auto lambda = [value = std::move(ptr)] {return *value;};

 

일반화된 캡처(C++ 14)

 

C++14에서는 해당 변수가 반드시 람다 함수의 바깥쪽 범위에 존재하지 않아도 캡처 절에 새 변수를 도입하고 초기화할 수 있습니다. 이러한 초기화는 임의의 식으로 표현할 수 있습니다. 새 변수의 형식은 식에서 생성되는 형식에서 추론됩니다. 이 기능을 사용하면 주변 범위에서 이동 전용 변수(예: std::unique_ptr)를 캡처하고 람다에서 사용할 수 있습니다.

pNums = make_unique<vector<int>>(nums);
//...
      auto a = [ptr = move(pNums)]()
        {
           // use ptr
        };

 

Lambda expression을 모르는 사람들을 위해 설명을 추가한다.

 

C++11에서는 재사용하지 않고 이름을 지정할 가치가 없는 짧은 코드 조각에 사용할 수 있는 인라인 함수를 작성할 수 있도록 람다 표현식을 도입했다.

 

가장 간단한 형태의 람다 표현식은 다음과 같이 정의할 수 있다.

 

[ capture clause ] (parameters) -> return-type  
{   
   definition of method   
}

일반적으로 람다 식의 return 타입은 컴파일러 자체에서 명시되며 명시적으로 지정할 필요가 없으며 -> return-type 부분을 무시할 수 있지만 조건문과 같이 복잡한 경우 컴파일러에서 반환을 확인할 수 없다. 이 경우에는 유형을 지정해야 한다.

 

auto square = [](int i)
{
    return i * i;
};
cout << "Square of 5 is : " << square(5) << endl;

위의 예제와 같이 return-type을 지정하지 않아도 상관없다.

 

람다 식은 바깥쪽 범위에서 변수에 엑세스할 수 있으므로 일반 함수보다 더 많은 기능을 가질 수 있다.

세 가지 방법으로 범위를 둘러싸는 외부 변수를 캡처할 수 있다.

1. 참조로 캡처

2. value로 캡처

3. 둘다 캡처(혼합 캡처) 

 

변수 캡처에 사용되는 구문:

[&] : 모든 외부 변수를 참조로 캡처

[=] : value로 모든 외부 변수를 캡처

[a, &b] : value로 캡처하고 참조로 b 캡처

[ ] : 해당 변수에 로컬인 변수에만 액세스 가능

 

#include <bits/stdc++.h>
using namespace std;
 
int main()
{
    vector<int> v1 = {3, 1, 7, 9};
 
    //  참조로 캡처
    auto pushinto = [&] (int m)
    {
        v1.push_back(m);
    };
 
    // 실제로 v1에 10을 저장
    pushinto(10);
 
    int N = 5;
 
    // [=]은 모든 외부 변수에 value로 캡처 가능
    int count_N = count_if(v1.begin(), v1.end(), [=](int a)
    {
        return (a >= N);
    });
 
    cout << "5보다 큰 숫자의 개수는? : "
         << count_N << endl;
}
//Output : 5보다 큰 숫자의 개수는 3

 

 

https://docs.microsoft.com/ko-kr/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170
https://en.wikipedia.org/wiki/C%2B%2B14#cite_note-9

 

300x250

댓글