HOWTO · C++

C++의 재귀 Lambda 함수

이 기사에서는 C++ 프로그래밍 언어의 재귀 람다 함수를 이해합니다.

이 페이지의 내용

이 기사에서는 C++에서 사용할 수 있는 재귀 람다를 이해합니다.

C++ 재귀 람다 함수

재귀란 함수가 자신을 (직간접적으로) 호출하는 과정을 말하며, 이 과정에 해당하는 함수를 재귀 함수라고 합니다. 재귀 람다 식은 이 프로세스의 결과입니다.

재귀 방법을 사용하여 일부 문제에 접근하면 훨씬 쉽게 해결할 수 있습니다.

로컬 코드를 재구성하는 과정에서 람다는 유용한 도구입니다. 반면에 내부에서 람다를 활용하고 싶은 경우가 있습니다.

이는 두 가지 이유 중 하나로 수행될 수 있습니다: 직접 재귀를 활성화하거나 클로저가 연속으로 등록될 수 있도록 합니다. 현재 버전의 C++에서는 이 작업을 성공적으로 수행하기가 매우 어렵습니다.

C++에서 재귀 Lambda 함수 구현

첫 번째 단계에서는 필요한 라이브러리를 가져옵니다.

#include <functional>
#include <iostream>

main() 함수 내에서 int 유형의 변수를 초기화하고 정수 값을 할당합니다.

int main() { int anyNumber = 456789; }

그런 다음 void 유형의 함수를 생성하고 reverseByRecursiveLambda라는 이름을 지정합니다.

function<void()> reverseByRecursiveLambda;

이제 재귀 람다 함수로 reverseByRecursiveLambda 함수를 초기화합니다.

reverseByRecursiveLambda = [&]() {};

이 메서드 내에서 anyNumber의 정수 값이 0과 같으면 아무 것도 반환하지 않는다는 검사를 구현해야 합니다. 그렇지 않은 경우 함수는 다음 작업 집합으로 이동해야 합니다.

그런 다음 함수는 일련의 수학적 계산을 수행한 후 결과를 인쇄합니다. 마지막 단계로 reverseByRecursiveLambda()라는 함수를 다시 실행합니다.

if (anyNumber == 0) return;

cout << anyNumber % 10 << " ";
anyNumber /= 10;
reverseByRecursiveLambda();

이 함수가 실행을 완료한 후에는 main() 메서드 내에서 이 함수를 호출하기만 하면 됩니다.

int main() { reverseByRecursiveLambda(); }

완전한 소스 코드:

#include <functional>
#include <iostream>

using namespace std;

int main() {
  int anyNumber = 123456789;

  function<void()> reverseByRecursiveLambda;

  reverseByRecursiveLambda = [&]() {
    if (anyNumber == 0) return;

    cout << anyNumber % 10 << " ";
    anyNumber /= 10;
    reverseByRecursiveLambda();
  };

  reverseByRecursiveLambda();
}

출력:

9 8 7 6 5 4 3 2 1

std::function을 사용하는 C++ 재귀 Lambda 함수

std::function 클래스 템플릿은 다양한 용도로 사용할 수 있는 다형성 함수 래퍼입니다. 모든 람다 식 바인딩 식 또는 기타 함수 개체는 std::function 클래스의 인스턴스 내에서 저장, 복사 및 호출될 수 있습니다.

또한 이러한 인스턴스는 멤버 함수에 대한 포인터와 데이터 멤버에 대한 포인터를 보유할 수 있습니다.

다음 예제에서는 팩토리얼의 스냅샷을 찍어야 합니다. 그런 다음 람다 본문 내에서 참조할 수 있습니다.

예제 코드:

#include <functional>
#include <iostream>

int main() {
  const std::function<int(int)> factorial = [&factorial](int n) {
    return n > 1 ? n * factorial(n - 1) : 1;
  };

  std::cout << "The factorial of 5 is: " << factorial(5);
  return factorial(5);
}

출력:

The factorial of 5 is: 120

일반 람다를 사용하는 C++ 재귀 람다 함수

일반 람다 식은 auto 유형의 인수가 하나 이상 있는 람다 식을 나타냅니다.

이 옵션을 가능하게 한 일반 람다 표현식 덕분에 재귀 람다 함수를 만드는 데 std::function을 사용할 필요가 없습니다. 람다 식의 유형은 이름만으로 결정할 수 없습니다.

따라서 C++14가 출시되기 전에는 std::function 안에 재귀 람다 식을 포함해야 했습니다. std::function에 종속되지 않으며 숫자 기본 유형에서 제대로 수행하기 위해 데이터를 캡처할 필요가 없습니다.

예제에서는 일반 람다 auto를 사용하여 map에 저장된 데이터를 표시하는 방법을 보여줍니다.

예제 코드:

#include <algorithm>
#include <iostream>
#include <map>
#include <string>

int main() {
  const std::map<std::string, int> numbers{
      {"Saad", 22}, {"Zaryab", 23}, {"Zeeshan", 24}};

  std::for_each(std::begin(numbers), std::end(numbers), [](const auto& entry) {
    std::cout << "Name: " << entry.first << "   Age: " << entry.second << '\n';
  });
}

GCC 11.1.0은 이 데모에서 사용되는 컴파일러의 이름입니다.

출력:

Name: Saad   Age: 22
Name: Zaryab   Age: 23
Name: Zeeshan   Age: 24

y_combinator를 사용하는 C++ 재귀 Lambda 함수

익명 함수(람다라고도 함)는 논리가 간단하고 명명된 함수로 추출되어야 하는 경우에만 사용하기 위한 것이므로 람다 내에서 재귀 호출이 이루어질 가능성은 거의 없습니다.

그러나 재귀를 사용할 수 없다고 상상해 봅시다. 함수가 우리 언어에서 일급 시민으로 취급되는 한(변수에 할당되고, 인수로 제공되고, 다른 객체처럼 반환될 수 있음) 우리는 여전히 재귀 구현을 작성할 수 있습니다.

Y 결합자는 이러한 목적에 유용한 고차 함수입니다. 불길하게 들리는 이름에도 불구하고 다른 함수를 감싸는 함수인 고차 함수일 뿐입니다.

다음은 피보나치 수열을 나열하기 위해 y 결합자를 사용하여 재귀 람다 함수를 생성한 예입니다.

예제 코드:

#include <iostream>

template <typename Function>
struct YCombinator {
  Function yFunction;

  template <typename... Args>
  decltype(auto) operator()(Args&&... args) {
    return yFunction(*this, std::forward<Args>(args)...);
  }
};

template <typename Function>
decltype(auto) make_YCombinator(Function f) {
  return YCombinator<Function>{f};
}

int main() {
  auto fib = make_YCombinator([](auto self, int n) {
    if (n < 2) return 1;
    return self(n - 1) + self(n - 2);
  });

  for (int i = 0; i < 10; ++i)
    std::cout << "fib(" << i << ") = " << fib(i) << "\n";

  return 0;
}

GCC 11.1.0은 이 데모에서 사용되는 컴파일러의 이름입니다.

출력:

fib(0) = 1
fib(1) = 1
fib(2) = 2
fib(3) = 3
fib(4) = 5
fib(5) = 8
fib(6) = 13
fib(7) = 21
fib(8) = 34
fib(9) = 55