Notice
Recent Posts
Recent Comments
Link
«   2026/05   »
1 2
3 4 5 6 7 8 9
10 11 12 13 14 15 16
17 18 19 20 21 22 23
24 25 26 27 28 29 30
31
Archives
Today
Total
관리 메뉴

로또

람다 함수 본문

언어

람다 함수

아롱로또 2023. 8. 30. 15:05

작성 이유

 알고리즘을 풀거나 javascript를 사용할 때 자주 등장하는 람다 함수에 대해 자세히 알고 싶었다.

 

정의

 함수에 인수로 호출되거나 전달되는 위치에서 바로 익명 함수 개체(클로저)를 정의하는 방법.

 

구조

[<Capture>] (<Parameter>) <mutable> <exception-specification> -> <trailing-return-type>
{
	lambda body
}

 

<Capture>

람다는 본문에 새 변수를 도입하거나 주변 범위의 변수에 접근하기 위해 Capture를 사용할 수 있다.

람다는 Capture절로 시작하는데, 캡처되는 변수가 값에 의한 것인지, 참조에 의한 것인지 지정할 수 있다.

람다 함수 밖의 지역 변수를 사용하려면 캡처 목록에 추가해야 한다.

Capture에 변수명을 다음과 같이 넣으면, 값을 복사하여 람다 함수가 호출된다.

int main(){
    string s = "main func value";
    cout << "In main, s Address: " << &s << endl;

    [s](){
        cout << "In Lambda, s Address: " << &s << endl;
    }();
}

Call by Value

하지만 다음과 같이 & 연산자를 붙인다면, 값을 참조하여 람다 함수가 호출됨을 확인할 수 있다.

int main(){
    string s = "main func value";
    cout << "In main, s Address: " << &s << endl;

    [&s](){
        cout << "In Lambda, s Address: " << &s << endl;
    }();
}

Call by Reference

[=]: 모든 외부 변수를 값에 의해 복사하여 람다 함수 내에서 사용할 수 있다.

[&]: 모든 외부 변수를 참조하여 람다 함수 내에서 사용할 수 있다.

<Parameter>

함수를 호출할 때 필요한 Parameter를 담는다.

int main(){
    [](int a, int b){
        cout << "Param a: " << a << endl;
        cout << "Param b: " << b << endl;
    }(2, 3);
}

Parameter

 

<Mutable>

기본적으로 Capture한 변수는 Const로 설정된다.

때문에 Capture한 변수를 수정하게 되면 오류가 발생한다.

mutable을 적용하지 않음
mutable을 적용하지 않음

 

하지만, Mutable을 사용하면 Capture한 값을 수정 가능하게 만들기 때문에 오류가 발생하지 않는다. 

int main()
{
    int captured = 10;

    [captured] (int param) mutable{
        captured++;
        param++;
        cout << captured << endl;
        cout << param << endl;
    }(5);
}

<Exception-specificion>

일반 함수에서와 동일하게 함수에서 발생할 수 있는 예외를 명시할 수 있다.

int main() {
    auto lambda = []() {
       cout << "Inside lambda" <<endl;
        throw runtime_error("Exception inside lambda");
    };

    try {
        lambda();
    } catch (exception e) {
       cerr << "Caught exception: " << e.what() <<endl;
    }

    return 0;
}

lambda 함수 내에서 발생한 예외는 lambda함수를 호출한 상위  호출자에 전달된다.

예외의 전달

예를 들어, noexcept 는 해당 함수에서는 예외가 발생하지 않음을 나타낸다. 또한 예외가 발생하더라도 상위 호출자에 예외가 전달되지 않는다.

int main() {
    auto lambda = []() noexcept{
       cout << "Inside noexcept lambda" <<endl;
        throw runtime_error("Exception inside noexcept lambda");
    };

    try {
        lambda();
    } catch (exception e) {
       cerr << "Caught exception: " << e.what() <<endl;
    }

    return 0;
}

noexcept 시 발생하는 예외

 

<Trailing-return-type>

번역하면 후행 반환 형식이다.

auto 로 정의된 함수의 return type을 명시적으로 알려주는 역할을 한다. 때문에 함수의 return type을 auto로 지정하지 않으면 사용할 필요가 없다.

auto 를 return하도록 정의된 람다 함수(lambda_func, lambda_func2)의 경우에 단일 return 식이라면 컴파일러는 반환 형식을 추론할 수 있지만 그렇지 않으면 컴파일러는 return type을 void로 추론하기 때문에 오류가 발생한다.

단일 return식이 아닌 lambda_func3에서 오류가 발생하는 모습

다음과 같이, lambda_func3에 trailing-return-type으로 pair<int, int> 를 명시해주면 오류가 사라진다.

int main() {
    auto lambda_func = [](int a, int b) {
        return make_pair(a, b);
    };

    auto lambda_func2 = [](int a){
        return a;
    };

    auto lambda_func3 = []() -> pair<int, int>{
        return {1, 2};
    };

    auto v1 = lambda_func(10, 20);
    cout << v1.first << ", " << v1.second << endl;

    auto v2 = lambda_func2(2);
    cout << v2 << endl;

    auto tmp = lambda_func3();
    cout << tmp.first << ", " << tmp.second << endl;
    return 0;
}

실행 결과

 

정리

Capture를 통해 외부 변수를 값이나 참조 형식으로 받아와 사용할 수 있다. [=]이나 [&]를 사용하면 외부 변수를 하나하나 명시하지 않아도 값이나 참조 형식으로 받아올 수 있다.

 

Parameter를 통해 인자를 전달받을 수 있다.

 

기본적으로 Capture를 통해 받은 변수는 Const 형태이지만 Mutable을 사용하면 Const 속성을 제거할 수 있다.

 

다른 일반 함수처럼 발생 가능한 예외를 명시할 수 있으며, noexcept를 사용하면 예외가 상위로 전달되지 않는다.

 

auto를 return-type으로 지정하면서 단일 return문이 아니라면, trailing return type을 명시해주어야 한다.

int main() {
    string s = "Main String";

    [&s](int a) mutable noexcept -> pair<int, int>{
        cout << "paramter a: " << a << endl;
        s = "Lambda String";
    }(100);

    cout << s << endl;
}

 

 

참고자료

https://learn.microsoft.com/ko-kr/cpp/cpp/lambda-expressions-in-cpp?view=msvc-170 

 

C++ 람다 식

자세한 정보: C++의 람다 식

learn.microsoft.com

https://blockdmask.tistory.com/491

 

[C++] 람다 표현식, lambda에 대해서

안녕하세요. BlockDMask입니다. 오늘은 C++11, 14에서 추가된 lambda 표현식에 대해 알아보겠습니다. 1. 람다 표현식 2. 람다 표현식 사용 방법과 구조 3. 람다의 필요성, 사용 예제 1. C++ 람다 표현식 lambda

blockdmask.tistory.com

https://m.blog.naver.com/sjg03179/220680619548

 

[C++11] auto, decltype, trailing return type

auto 정의 : 값에 상응하는 형식을 [컴파일 타임]에 추론해 주는 키워드이다. vector<string>::const...

blog.naver.com

 

'언어' 카테고리의 다른 글

Cast  (0) 2023.11.08
STL  (1) 2023.10.29
Template  (0) 2023.10.29
스마트 포인터  (0) 2023.09.20
가상 함수  (0) 2023.09.04