Menu
Coddy logo textTech

std::function과 std::bind

Coddy C++ 여정의 객체 지향 프로그래밍 섹션에 포함된 레슨. 104개 중 86번째.

람다는 강력하지만, 때로는 서로 다른 유형의 호출 가능한 객체를 일관된 방식으로 저장하거나 기존 함수를 필요한 시그니처에 맞게 조정해야 합니다. std::functionstd::bind<functional> 헤더에서 제공되며 이러한 문제를 해결합니다.

std::function은 특정 시그니처와 일치하는 모든 호출 가능한 대상을 담을 수 있는 타입 소거 래퍼입니다 - function, 람다 또는 함수 객체:

#include <iostream>
#include <functional>

int add(int a, int b) { return a + b; }

int main() {
    std::function<int(int, int)> operation;
    
    operation = add;                              // 일반 함수
    std::cout << operation(3, 4) << "\n";        // 7
    
    operation = [](int a, int b) { return a * b; }; // 람다
    std::cout << operation(3, 4) << "\n";        // 12
}

std::bind는 기존 function의 일부 arguments를 고정하여 새로운 호출 가능 객체를 생성합니다. 계속해서 변경되는 arguments를 표시하려면 std::placeholders::_1, _2 등을 사용하세요:

#include <iostream>
#include <functional>

void greet(const std::string& greeting, const std::string& name) {
    std::cout << greeting << ", " << name << "!\n";
}

int main() {
    using namespace std::placeholders;
    
    auto sayHello = std::bind(greet, "Hello", _1);
    sayHello("Alice");  // Hello, Alice!
    
    auto swapped = std::bind(greet, _2, _1);
    swapped("Bob", "Hi");  // Hi, Bob!
}

이러한 도구는 OOP에서 콜백을 클래스 멤버로 저장하거나 Strategy 패턴을 구현할 때 특히 유용합니다. 하지만 최신 C++에서는 가독성과 성능을 향상하기 위해 std::bind보다 람다를 선호하는 경우가 많습니다. 인수를 재정렬하거나 레거시 코드와 작업해야 할 때 주로 std::bind를 사용하세요.

challenge icon

챌린지

쉬움

std::functionstd::bind의 강력한 기능을 Demonstrate하는 Configure 가능한 calculator를 만들어 보겠습니다. 수학 연산을 런타임에 저장하고, 교체하고, 사용자 지정할 수 있는 시스템을 Create하여 이러한 도구가 유연한 callback 관리 기능을 어떻게 제공하는지 살펴봅니다.

코드를 세 개의 파일로 구성합니다:

  • MathOperations.h: operation library로 사용할 독립적인 수학 function 모음을 Define합니다.

    다음 function을 Create합니다:

    • add(int a, int b): 합을 반환
    • subtract(int a, int b): difference (a - b)를 반환
    • multiply(int a, int b): 곱을 반환
    • power(int base, int exponent, int multiplier): multiplier * (base ^ exponent)를 반환합니다. power를 calculate하기 위해 간단한 loop를 사용합니다 (음이 아닌 exponents라고 assume합니다).
  • Calculator.h: std::function을 사용하여 operation을 동적으로 저장하고 실행하는 Calculator class를 Define합니다.

    Calculator에는 다음이 있어야 합니다:

    • current binary operation을 저장하는 private member std::function<int(int, int)>
    • setOperation(std::function<int(int, int)> op): current operation을 설정
    • calculate(int a, int b): 저장된 operation을 Executes하고 결과를 반환

    필요한 header(<functional>)를 include하고 MathOperations header도 반드시 include하세요.

  • main.cpp: 세 개의 inputs를 읽습니다:
    1. Operation 이름: add, subtract, multiply 또는 square
    2. first number (integer)
    3. second number (integer)

    Calculator를 Create하고 operation 이름에 따라 Configure합니다:

    • add, subtract, multiply의 경우: corresponding function을 calculator에 directly assign합니다.
    • square의 경우: std::bind를 사용하여 exponent 2와 multiplier 1을 always 사용하는 power의 specialized version을 Create합니다. bound function은 두 arguments를 받아야 하며, first만 base로 사용합니다 (second argument는 placeholder를 사용하여 무시할 수 있습니다).

    operation을 설정한 후, 두 숫자로 calculate()을 Call하고 다음을 출력합니다:

    Result: [value]

    그런 다음 a + b + 100을 반환하는 lambda를 calculator에 assign하고, 동일한 inputs로 실행한 뒤 다음을 출력하여 operation을 swapping하는 과정을 Demonstrate합니다:

    With bonus: [value]

예를 들어, inputs가 add, 10, 5인 경우:

Result: 15
With bonus: 115

inputs가 multiply, 7, 3인 경우:

Result: 21
With bonus: 110

inputs가 square, 4, 0인 경우:

Result: 16
With bonus: 104

이 challenge는 std::function이 서로 다른 callable type(일반 function, bound function 및 lambda)을 저장하는 uniform한 방법을 제공하는 반면, std::bind는 일부 arguments를 고정하여 기존 function을 adapt할 수 있게 해 준다는 것을 보여 줍니다.

직접 해보기

#include <iostream>
#include <string>
#include <functional>
#include "Calculator.h"

using namespace std;

int main() {
    // 입력 읽기
    string operation;
    int num1, num2;
    cin >> operation >> num1 >> num2;
    
    // Calculator 인스턴스 생성
    Calculator calc;
    
    // TODO: 연산 이름에 따라 계산기를 구성하세요
    // "add", "subtract", "multiply"의 경우: 해당 함수를 직접 할당하세요
    // "square"의 경우: std::bind를 사용하여 power의 특수화된 버전을 만드세요
    //   항상 지수 2와 승수 1을 사용하는
    //   힌트: 밑 인수에 std::placeholders::_1을 사용하세요
    
    if (operation == "add") {
        // 여기에 코드를 작성하세요
    } else if (operation == "subtract") {
        // 여기에 코드를 작성하세요
    } else if (operation == "multiply") {
        // 여기에 코드를 작성하세요
    } else if (operation == "square") {
        // 여기에 코드를 작성하세요 - power 함수와 함께 std::bind를 사용하세요
    }
    
    // TODO: calculate()를 호출하고 결과를 출력하세요
    // 형식: "Result: [value]"
    
    // TODO: 연산 교체를 시연하세요
    // a + b + 100을 반환하는 람다를 계산기에 할당하세요
    // calculate()를 다시 호출하고 결과를 출력하세요
    // 형식: "With bonus: [value]"
    
    return 0;
}
quiz icon실력 점검

이 레슨에는 짧은 퀴즈가 포함되어 있습니다. 레슨을 시작해 문제를 풀고 진행 상황을 기록하세요.

객체 지향 프로그래밍의 모든 레슨

직접 연습해 보세요: 온라인 C++ 컴파일러