코딩 62일차 C/C++

마스터피스·2024년 1월 31일
0

C/ C++ 

목록 보기
34/35
post-thumbnail

람다함수

1) 람다 함수의 필요성

  • 람다 함수는 익명 함수라고 불리고 여러 가지 설명이 있는데, 그냥 간단히 말해서 함수인데 변수입니다. 정확한 설명은 아닌데 그냥 함수인데 변수라고 생각하면 됩니다. 함수를 '변수처럼' 취급하기 위한 테크닉이 된다고 생각하시면 되겠습니다.

ex)

#include <cstdio>
#include <functional>

int main() {

    std::function<void()> foo = [=]() {
        printf("Hello World");
        };

    return 0;
}

2) #include functional

  • 람다 함수를 사용하기 위해서는 functional 헤더파일을 포함해야 합니다.이 헤더파일이 없다고 해서 람다 함수를 사용할 수 없는 것은 아니지만 이 헤더파일이 없으면 std::function을 사용할 수 없기 때문에 사용하기 매우 불편합니다

3) Lambda 함수의 구조

  • 람다 함수는 이와 같은 구조를 갖고 있습니다.캡쳐는 람다 함수 몸통 외부의 값을 가져오기 위해 사용되는 부분입니다.파라미터는 람다 함수의 함수 파라미터를 정의하게 됩니다. 리턴은 람다 함수의 리턴값을 의미하며, { ... } 브라켓은 람다 함수의 실제 동작을 담당하는 부분이 됩니다. 이 부분에서 캡쳐는 일반적으로 [ = ] 으로 고정됩니다.

예제코드)

#include <cstdio>
#include <functional>

int main() {

    int myvalue = 100;

    // 함수의 타입을 지정해주는것.
    // 파라미터는 void () 안에 입력후 같은 타입을 입력해준다
    // std::string<void>(int, float) foo = [=](int value1, float value2) {}
    std::function<void()> foo = [=]() {
        printf("Hello World, %d", myvalue);
        };

    myvalue = 200;

    foo();

    return 0;
}

위에코드가 너무 길어지기 때문에 아래와 같이 바꿀수 있다. (auto로)
예제코드)

#include <cstdio>
#include <functional>

int main() {

    int myvalue = 100;

    // 함수의 타입을 지정해주는것.
    // 파라미터는 void () 안에 입력후 같은 타입을 입력해준다
    // std::string<void>(int, float) foo = [=](int value1, float value2) {}
    auto foo = [=]() {
        printf("Hello World, %d", myvalue);
        };

    myvalue = 200;

    foo();

    return 0;
}

4) std::function 의 템플릿 타입

  • 람다 함수는 std::function 형태의 변수로 변수화가 될 수 있습니다. 함수가 변수화가 되며, 이 변수의 템플릿 타입은 리턴타입과 파라미터 타입의 나열이 됩니다.
    예를 들자면 리턴타입이 bool 이고 파라미터들이 int, float 를 받는다면 std::function의 템플릿 타입은std::function<bool(int, float)>이 됩니다.

ex)

#include <cstdio>
#include <functional>

int main() {

    int myvalue = 100;

    // 함수의 타입을 지정해주는것.
    // 파라미터는 void () 안에 입력후 같은 타입을 입력해준다
    // std::string<void>(int, float) foo = [=](int value1, float value2) {}
    auto foo = [=](int value1, int value2) {
        return value1 + value2;
        };

    myvalue = 200;

    foo();

    return 0;
}

5) std::bind

  • std::bind를 활용하게 되면 기존에 존재하는 함수를 끌어와서 std::function 형태의 클래스 인스턴스로 지정할 수 있게 됩니다. 쉽게 말하자면 함수를 변수로 지정할 수 있게 된다는 의미입니다. 이를 활용해 람다 함수를 활용하지 않고도 함수의 변수를 만들어낼 수 있습니다. 다만 클래스 내부에서는 std::bind를 사용할 때 약간 다른 점이 있습니다. 클래스의 정의 앞에 앰퍼샌드를 붙여줘야 하며(함수의 주소값을 필요로 합니다), 이 함수를 실행할 클래스 인스턴스 그 자체도 std::bind의 파라미터로 넘겨줘야 하죠.

// std::bind를 이용해 파라미터를 만들땐 꼭 ,로 std::placeholders::_1부터 변수의 개수만큼 맞춰줘야한다.

예제코드)

#include <cstdio>
#include <functional>
#include <string>

void foo() {
    printf("Hello World");

}

int sum(int value1, int value2) {
    return value1 + value2;
}
int main() {
    // std::bind를 이용해 파라미터를 만들땐 꼭 오른쪽에 ,로 std::placeholders::_1부터
    // 변수의 개수만큼 맞춰줘야 한다.
    auto local_sum = std::bind(sum, std::placeholders::_1, std::placeholders::_2);
    int result = local_sum(10, 20);
    printf("result : %d", result);



    return 0;
}

클래스를 바인딩 할때)
예제코드)

#include <cstdio>
#include <functional>
#include <string>

void foo() {
    printf("Hello World");

}

int sum(int value1, int value2) {
    return value1 + value2;
}

class Marine{
public:
    void attackTo(const char* target) {
        printf("마린은 %s 를 공격했다.\n", target);
    }
};

int main() {

    Marine* m = new Marine();

    auto attack = std::bind(&Marine::attackTo, m, std::placeholders::_1);
    attack("히드라");


    return 0;
}

6) 도대체 이런 일을 왜 해야 할까

  • 우리가 흔히 현업에서 개발을 하다 보면 콜백을 쓰게 됩니다. 이 콜백의 대표적인 예로는 네트워크 응답이 있습니다. 일반적으로 우리가 프로그램을 만들게 되고 응답을 기다리게 되면 이 응답을 기다리는 동안 프로그램은 멈춰있게 됩니다. 응답을 기다리는 동안 다음 일을 못 하게 막고 있게 되기 때문이죠. 이 응답을 기다리는 대신 일을 요청하고, 요청한 결과가 처리가 되었을 때 처리할 내용이 담긴 함수를 '변수'로 지정해서 넘겨주게 되면 네트워크 처리 루틴이 일을 처리하고 마지막에 우리가 넘겨준 '함수 변수'를 자동으로 실행하면서 우리가 원하는 동작을 할 수 있게 되는 것이죠. 이를 위해 우리는 람다식이나 함수를 담고 있는 변수를 만들게 됩니다.
profile
코딩 일지

0개의 댓글