0Pricing
C++ Academy · 강의

호출 대상 선택하기

람다, bind 및 포인터 비교하기

호출 대상 선택하기은(는) CoddyKit의 무료 C++ Academy 강의입니다. 이것은 4개 중 4번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 C++ Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. C++ Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

호출 가능 객체 도구 상자

C++에서는 동작을 전달하는 여러 방법을 제공합니다. 함수 포인터, 람다, 함수 객체, std::bind, std::function이 있습니다. 각각 적합한 용도가 다릅니다.

  • 일반적으로 속도와 유연성 사이에서 절충해야 합니다.
  • 가독성도 중요합니다.
#include <iostream>

int twice(int x) { return x * 2; }

int main() {
    int (*fp)(int) = twice;
    auto lam = [](int x) { return x * 2; };
    std::cout << fp(5) << ' ' << lam(5) << '\n';
    return 0;
}

함수 포인터를 사용하는 경우

작고 상태가 없는 콜백이 필요하고 C 호환성이나 오버헤드 없는 동작을 원할 때 함수 포인터를 사용하세요.

#include <iostream>

void logMsg(const char* m) { std::cout << "LOG: " << m << '\n'; }

int main() {
    void (*handler)(const char*) = logMsg;
    handler("started");
    return 0;
}

람다를 사용하는 경우

람다는 현대적인 기본 선택입니다. 간결하고 상태를 캡처할 수 있으며, 템플릿과 알고리즘에서 컴파일러가 잘 인라인할 수 있습니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    std::vector<int> v = {3, 1, 4, 1, 5};
    std::sort(v.begin(), v.end(), [](int a, int b) { return a > b; });
    for (int x : v) std::cout << x << ' ';
    std::cout << '\n';
    return 0;
}

람다에서 상태 캡처하기

람다는 주변 변수를 캡처하지만 함수 포인터는 그렇게 할 수 없습니다. 따라서 문맥을 인식하는 콜백에 적합합니다.

#include <iostream>
#include <vector>
#include <algorithm>

int main() {
    int threshold = 3;
    std::vector<int> v = {1, 2, 3, 4, 5};
    int c = std::count_if(v.begin(), v.end(), [threshold](int x) { return x > threshold; });
    std::cout << c << '\n';
    return 0;
}

함수 객체를 사용하는 경우

함수 객체(operator()를 가진 구조체)는 설정을 보유할 수 있고 여러 곳에서 사용할 수 있는, 재사용 가능한 이름 있는 연산에 적합합니다.

#include <iostream>
#include <vector>
#include <algorithm>

struct AboveThreshold {
    int limit;
    bool operator()(int x) const { return x > limit; }
};

int main() {
    std::vector<int> v = {1, 5, 2, 8};
    std::cout << std::count_if(v.begin(), v.end(), AboveThreshold{4}) << '\n';
    return 0;
}

람다와 bind 비교

둘 다 인수를 미리 채울 수 있습니다. 람다 방식이 일반적으로 더 명확하고 컴파일러가 최적화하기도 쉬우므로 std::bind보다 람다를 선호하세요.

#include <iostream>

int power(int base, int exp) {
    int r = 1;
    for (int i = 0; i < exp; ++i) r *= base;
    return r;
}

int main() {
    auto square = [](int x) { return power(x, 2); };
    std::cout << square(6) << '\n';
    return 0;
}

std::function을 사용하는 경우

구체적인 형식을 알 수 없는 호출 가능 객체를 저장해야 할 때 std::function을 사용하세요. 예를 들어 클래스 멤버나 컨테이너에 저장할 때 사용합니다.

#include <iostream>
#include <functional>
#include <vector>

int main() {
    std::vector<std::function<int(int)>> pipeline;
    pipeline.push_back([](int x) { return x + 1; });
    pipeline.push_back([](int x) { return x * 3; });
    int v = 2;
    for (auto& f : pipeline) v = f(v);
    std::cout << v << '\n';
    return 0;
}

템플릿으로 오버헤드 피하기

함수가 호출 가능 객체를 받기만 하고 저장하지 않는다면, 템플릿 매개변수를 사용하여 형식 소거를 피하고 최대 속도를 유지할 수 있습니다.

#include <iostream>

template <typename F>
int applyTwice(int x, F f) { return f(f(x)); }

int main() {
    std::cout << applyTwice(3, [](int n) { return n + 10; }) << '\n';
    return 0;
}

성능 순위

대략적으로 템플릿 기반 호출 가능 객체나 캡처가 없는 람다가 가장 빠르고, 함수 포인터가 그에 가깝습니다. std::function은 간접 호출과 메모리 할당 가능성 때문에 가장 느립니다.

#include <iostream>
#include <functional>

int main() {
    auto fast = [](int x) { return x + 1; };
    std::function<int(int)> flexible = fast;
    std::cout << fast(1) << ' ' << flexible(1) << '\n';
    return 0;
}

선택 가이드

빠른 가이드:

  • 호출 가능 객체를 무엇이든 저장해야 하나요? std::function을 사용하세요.
  • 제네릭 함수에서 하나를 받기만 하나요? 템플릿 매개변수를 사용하세요.
  • 상태가 있는 동작을 인라인으로 정의하나요? 람다를 사용하세요.
  • C API를 사용하거나 상태가 없나요? 함수 포인터를 사용하세요.
#include <iostream>
#include <functional>

void runStored(const std::function<void()>& cb) { cb(); }

template <typename F>
void runGeneric(F f) { f(); }

int main() {
    runStored([] { std::cout << "stored\n"; });
    runGeneric([] { std::cout << "generic\n"; });
    return 0;
}

모두 함께 사용하기

작은 이벤트 시스템은 핸들러를 제네릭하게 받은 다음 std::function에 저장하여 나중에 호출할 수 있게 만들 수 있습니다.

#include <iostream>
#include <functional>
#include <vector>

struct Dispatcher {
    std::vector<std::function<void(int)>> handlers;
    template <typename F> void on(F f) { handlers.emplace_back(f); }
    void fire(int e) { for (auto& h : handlers) h(e); }
};

int main() {
    Dispatcher d;
    d.on([](int e) { std::cout << "got " << e << '\n'; });
    d.fire(7);
    return 0;
}

빠른 확인

호출 가능 객체 선택에 대한 이해도를 확인해 보세요.

복습

호출 가능 객체를 선택하는 방법을 배웠습니다.

  • 상태가 없고 C와 호환되는 콜백에는 함수 포인터
  • 인라인으로 상태가 있는 동작을 정의할 때는 기본적으로 람다
  • 재사용 가능한 이름 있는 연산에는 함수 객체
  • 호출 가능 객체를 받기만 할 때는 가장 빠른 템플릿 매개변수
  • 형식을 알 수 없는 호출 가능 객체를 저장해야 할 때는 std::function

이것으로 함수 객체 및 std::bind 과정이 끝났습니다.

자주 묻는 질문

“호출 대상 선택하기” 강의는 무료인가요?

네 — “호출 대상 선택하기” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 C++ Academy 강의 전체를 잠금 해제할 수 있습니다. C++ Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“호출 대상 선택하기”에서 뭘 배우나요?

람다, bind 및 포인터 비교하기 브라우저에서 직접 실행하는 실습 코드로 C++ Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

C++ Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 C++ Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 4번째 강의입니다.

“호출 대상 선택하기” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 C++ Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 C++ Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. 함수 포인터
  2. std::function
  3. std::bind
  4. 호출 대상 선택하기
← C++ Academy(으)로 돌아가기