std::function - 호출 가능한 모든 것을 위한 래퍼
개요
std::function
은 C++11부터 도입된 표준 라이브러리의 기능으로, 함수 포인터, 함수 객체(Functor), 람다 표현식 등 호출 가능한(callable) 모든 것을 저장하고, 감싸고, 호출할 수 있는 다형성 래퍼(polymorphic wrapper)입니다. 이를 통해 다양한 형태의 호출 가능한 객체를 동일한 인터페이스로 처리할 수 있어 코드의 유연성과 재사용성을 크게 향상시킵니다.
C++ 버전별 주요 키워드 도입 시기
- C++11 :
std::function
이 처음 도입되었습니다.
내용 설명
std::function
은 템플릿 클래스로, std::function<ReturnType(ArgTypes...)>
와 같은 형태로 선언합니다.
ReturnType
: 함수의 반환 타입ArgTypes...
: 함수의 인자 타입 목록
주요 특징
- 타입 소거 (Type Erasure)
std::function
은 서로 다른 타입의 호출 가능한 객체(예: 일반 함수, 람다, 함수 객체)를 동일한std::function
타입의 객체에 저장할 수 있습니다.- 컴파일 타임에 구체적인 타입을 숨기고, 런타임에 동일한 방식으로 호출할 수 있게 해줍니다.
- 다형성 (Polymorphism)
- 다양한 호출 가능 객체를
std::function
객체에 할당하고, 이를 통해 동일한 인터페이스로 호출할 수 있습니다. - 이러한 특징은 콜백(callback) 함수나 이벤트 핸들러, 전략(Strategy) 패턴 등을 구현할 때 매우 유용합니다.
- 다양한 호출 가능 객체를
- 상태 저장 (State Storage)
- 람다 표현식과 함께 사용될 때, 캡처된 변수([&] 또는 [=] 등으로 캡처)를 포함한 람다의 상태를 안전하게 저장할 수 있습니다.
주의사항
std::function
은 내부적으로 동적 할당을 사용할 수 있으므로(Small Buffer Optimization으로 작은 크기의 객체는 스택에 저장하기도 함), 일반 함수 포인터나 람다를 직접 사용하는 것보다 약간의 성능 오버헤드가 발생할 수 있습니다. 따라서 성능이 매우 중요한(performance-critical) 코드에서는 사용에 신중을 기해야 합니다.
예제 코드
#include <functional>
#include <iostream>
#include <vector>
// 일반 함수
int f(int arg)
{
std::cout << "f(" << arg << ") called\n";
return ++arg;
}
// std::function을 인자로 받는 함수
int new_approach2(std::function<int(int)> func)
{
return func(2);
}
int main()
{
auto param = int{1};
// 1. C 스타일 함수 포인터
std::cout << "--- C-style function pointer ---\n";
int (*old_approach)(int);
old_approach = f;
old_approach(2);
// 2. std::function에 일반 함수 저장
std::cout << "\n--- std::function with a regular function ---\n";
auto new_approach = std::function{f};
auto result = new_approach(param);
std::cout << "Result from new_approach(param): " << result << '\n';
// 3. 함수에 std::function 전달
std::cout << "\n--- Passing a function to another function ---\n";
new_approach2(f);
// 4. std::function에 람다 표현식 저장
std::cout << "\n--- std::function with lambdas ---\n";
const int threshold = 2;
auto fns = std::vector<std::function<bool(const int)>>{
[&threshold](const int v) { return v > threshold; },
[&threshold](const int v) { return v < threshold; },
[&threshold](const int v) { return v == threshold; },
[&threshold](const int v) { return v != threshold; },
[&threshold](const int v) { return v >= threshold; },
[&threshold](const int v) { return v <= threshold; },
};
for (const auto &fn : fns)
{
std::cout << std::boolalpha << "Is 1 comparable? " << fn(1) << '\n';
}
return 0;
}
실행 결과
--- C-style function pointer ---
f(2) called
--- std::function with a regular function ---
f(1) called
Result from new_approach(param): 2
--- Passing a function to another function ---
f(2) called
--- std::function with lambdas ---
Is 1 comparable? false
Is 1 comparable? true
Is 1 comparable? false
Is 1 comparable? true
Is 1 comparable? false
Is 1 comparable? true
활용팁
- 콜백 시스템: GUI 라이브러리의 버튼 클릭 이벤트나 네트워크 라이브러리의 데이터 수신 이벤트 등 비동기적인 작업의 콜백 함수를 등록할 때
std::function
을 사용하면 다양한 형태의 콜백을 일관되게 처리할 수 있습니다. - 전략 패턴: 알고리즘의 특정 부분을 교체 가능하게 만들고 싶을 때, 알고리즘의 각 단계를
std::function
으로 정의하여 런타임에 동적으로 변경할 수 있습니다. - 상태를 갖는 함수 객체: 람다의 캡처 기능을 활용하여 상태를 저장하는 함수 객체를 만들고, 이를
std::vector<std::function<...>>
와 같은 컨테이너에 저장하여 관리할 수 있습니다. 예제 코드의fns
벡터가 좋은 예시입니다.
'개발 > C++ (98,03,11,14,17,20,23)' 카테고리의 다른 글
Modern C++ : std::min, max, equal, any_of, all_of, none_of (98, 11, 17) (0) | 2025.09.12 |
---|---|
Modern C++ : std::remove, std::sort, std::replace (98, 20) (1) | 2025.09.11 |
Modern C++ : std::transform & std::accumulate (98) (0) | 2025.09.10 |
Modern C++ : std::generate, local static variables (98, 11, 14) (0) | 2025.09.09 |
Modern C++ : Lambda Expressions (11, 14, 17, 20) (1) | 2025.09.08 |
Modern C++ : std::numeric_limits (98, 11, 17) (0) | 2025.09.07 |
Modern C++ : std::chrono 날짜 및 시간대 (11, 14, 17, 20) (1) | 2025.09.06 |
Modern C++ : std::chrono 시간 측정 (11, 14, 17, 20) (0) | 2025.09.05 |