관리 메뉴

기억을 위한 기록들

[CPP] 함수 객체(Functor)에 관하여 본문

C & CPP

[CPP] 함수 객체(Functor)에 관하여

에드윈H 2025. 8. 21. 13:24

 

 

함수 객체란 함수처첨 동작하는 객체를 뜻하며, 클래스의 객체가 () 연산자를 오버로딩해서 함수 호출처럼 쓸 수 있게 만든 것이다.

 

 

객체로 존재하므로 멤버변수를 넣어, 상태값을 가질수도 있다는 장점이 있다.

 

 

stl 사용 예시

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

struct Multiply {
    int factor;  // 곱할 값

    // 생성자로 상태 저장
    Multiply(int f) 
      : factor(f)
    {}

    // 함수 호출 연산자 오버로딩
    int operator()(int x) const 
    {
        return x * factor;
    }
};

int main() {
    std::vector<int> nums = {1, 2, 3, 4};

    Multiply mul2(2); // 2배 곱하는 Functor
    std::transform(nums.begin(), nums.end(), nums.begin(), mul2);

    for (int n : nums)
    {
    	std::cout << n << " "; // 출력: 2 4 6 8
    }
}

 

 

 

정리하자면 함수객체(Functor)는 상태를 가진 함수라고 생각하면 될 것 같다.

 

 

물론 함수라고 해서 정보를 보관할수 없는 건 아니지만, 한계가 있고 관리라는 측면으로 봤을 때, 함수보다 나은 점이 있다는 것이다.

 

 

언리얼엔진에서의 함수 객체 사용 예시 

언리얼엔진의 TArray 타입의 Sort 함수에서도 파라미터로 전달 받는 값이 함수 객체 형태로 되어 있다.

보통 람다함수를 넣어 바로 사용하지만,

TArray<FItem*> Items;

// Functor(람다)로 정렬 조건 전달
Items.Sort([](const FItem& A, const FItem& B) {
    return A.Grade > B.Grade;
});

 

 

Sort함수 내부모습를 살펴보면

전달받은 Predicate라는 변수를 TDereferenceWrapper라는 타입으로 한번 감싸주는데 해당 변수 타입을 살펴보면,

 

 

내부에서 operator() 연산자를 사용해서 적용하는 모습을 볼 수 있다.

 

그리하여 아래와 같이 사용도 가능하다. 

// 비교 펑터(Functor) 구조체
struct FSortByAbs
{
	FORCEINLINE bool operator()(const int32& A, const int32& B) const
	{
		return A < B;
	}
};

//..


void Example()
{
    TArray<int32> Numbers = { -10, 3, -7, 2, -5 };

    // 펑터 기반 정렬 (절댓값 기준 오름차순)
    Numbers.Sort(FSortByAbs());

    for (const int32 Num : Numbers)
    {
        UE_LOG(LogTemp, Log, TEXT("%d"), Num);
    }
}

 

그런데 사실 해당 비교 연산자로 엄청나게 많은 내용을 넣지 않기에 대부분 람다를 사용해서 쓰지만 혹시 재사용할 일이 많거나, 많은 내용을 비교해야 한다면 함수객체를 따로 선언해서 불러오는 것도 좋은 방법 같다.