개발하는 리프터 꽃게맨입니다.

[C++] 람다 식 (Lambda) 본문

언어/C, C++

[C++] 람다 식 (Lambda)

파워꽃게맨 2024. 1. 19. 00:04

[ 목차 ]

     

    1. 람다 표현식

    C++에서는 '호출할 수 있는 객체'를 callable이라고 말합니다.

    그 종류는 총 5개

     

    1) std::function

    2) 함수 포인터

    3) operator()

    4) bind에서 나온 타입 (아직 다루지 않은 내용)

     

    그리고 lambda 람다식입니다.

    새로운 '호출성 객체'라고 하죠,

     

    람다는 다른 언어에서는 익명함수, 무명함수라고 말하며

    기능적으로는 '재활용하지 않는 일회용 함수'라고 말합니다.

     

    이름이 없고, 필요할 때 딱 만들어서 쓰고 버리는 함수라고 할 수 있죠.

     

    예시는 아래와 같습니다.

     

    즉석 해서 함수를 정의한다고 보면 되겠습니다.

     

    이런 식으로 람다 변수로 초기화해서 호출하는 방법도 있고, 

    바로 호출하고 버리는 방법도 있고, 매개변수로 넘기는 방법도 있습니다.

     

    더 다양한 예시는 다음 목차에서 알아보도록 하겠습니다.

    2. 문법 살펴보기

     

    1) 캡처블록

    캡처블록은 [ ]로 감싼 부분입니다.

     

    (1) 빈 캡처블록

     

     

    캡처블록을 비워둘 시,

    람다 밖에 있는 변수에 대해 람다 내부에서 접근이 불가능합니다.

     

    (2) 값에 의한 캡처

     

    외부변수를 사용할 수 있습니다.

    단, 읽을 수만 있고 쓰기는 할 수 없습니다. (read only)

    만약, 읽은 값을 변경하려고 한다면, 에러가 발생합니다.

    기본적으로 const로 읽는다고 보시면 되겠습니다.

     

    (3) 참조에 의한 캡처

     

    외부변수를 사용할 수 있을 뿐 아니라 읽고 쓰기 둘 다 가능합니다.

    그러나, '참조'로 읽어오기 때문에 참조한 변수를 바꾸면 원본 변수의 데이터도 바뀝니다.

     

    (4) 특정 변수로 제한하기

     

     

    특정 변수만 읽고 싶으면, 이런 식으로 읽고 싶은 변수만 캡처 목록에 추가해서 읽을 수 있고

    어떤 형식으로 읽을지 하나하나 결정할 수 있습니다.

     

    2) 매개변수 목록

     

    매개변수 목록은 마치 진짜 함수를 정의하는 식으로 정의하면 됩니다.

    참고로 매개변수 목록가 void라면 아예 생략해도 상관없습니다.

    그러나 생략할 경우 가독성이 매우 떨어지기 때문에, 명시하는 것을 기본으로 합니다.

     

    3) mutable

     

    []()의 다음 부분은 specifiers(지정자)라고 말하는 부분인데,

    기본적으로는 생략되어 있으며

    mutable을 명시해 주면, 값에 의한 캡처를 수행할 때 외부 변수를 복사해서 읽어올 수 있습니다.

     

    즉, 진짜 함수처럼 매개변수를 복사 형식으로 들고 와서 사용할 수 있다는 것이죠.

    그래서 대입 등 쓰기(write)가 발생해도 원본 변수에는 어떤 영향도 미치지 않습니다.

     

    4) 리턴타입

     


    리턴 타입을 명시할 수 있습니다.

    생략도 가능한데 생략할 경우 컴파일러가 리턴 타입을 추론합니다.

     

    프로젝트마다 어떤 형식을 사용할지는 취향차이이며, 저는 명시하지 않는 편입니다.

     

    5) 호출방법

     

    대부분 f()처럼 함수처럼 호출하지만

    아래처럼 만들자마자 바로 호출하는 방법도 존재합니다.

    3. 사용 예시

    1) 매개변수로 전달

     

     

    템플릿 Sort 함수를 만들어서 비교를 위한 함수 객체로 람다를 전달하는 모습입니다.

     

     

     

    Good을 가격에 대한 오름차순으로 set에 저장하는 예시입니다.

    사실 보통 이 경우엔 함수 객체를 더 많이 사용합니다.

     

     

    람다가 가장 많이 쓰이는 예시가 아마 바로 std::algorithm을 사용할 경우일 겁니다.

    std::algorithm 특성상 유연하게 동작하기 때문에 람다를 사용하기에 가장 적합한 상황이라고 할 수 있겠습니다. 

     

    람다 식은 함수 매개변수로 전달할 때 빼고는 잘 사용하지 않습니다.

    장점만큼 단점도 분명한 문법이기 때문이죠.

    4. 장점과 단점

    1) 장점

    간단한 함수를 바르게 작성할 수 있다.

     

    2) 단점

    디버깅하기 힘들다. (call stack에 이상하게 잡힙니다.)

    함수의 재사용성이 낮다.

    가독성이 낮고, 함수처럼 생기지 않았기에 눈에 잘 띄지 않는다.

    이로 인해 '코드 중복'이 발생할 수 있다.

     

    3) 권장하는 사용법

    (1) 기본적으로 이름 있는 함수를 사용하자.

    (2) 재사용하지 않고, 매우 짧은 항수의 경우 람다를 사용하자.

    (3) std::alogorithm처럼 매개변수로 함수를 전달할 때 유용하게 사용할 수 있다.

     

    참고로 '람다'는 객체입니다.

    std::function 으로 관리할 수 있습니다.