[STL] 함수 객체 (less, greater)

치치·2025년 2월 13일

STL

목록 보기
7/21
post-thumbnail

함수 객체

이미 한번 했었더라 ,,, 근데 까먹어서 다시 정리하기!! https://velog.io/@yangju058/STL-연산자-오버로딩

  • 함수객체란, ()연산자를 오버로딩한 객체를 의미한다

  • 주로 '함수처럼 동작하는 클래스 객체'라고도 한다
    -> 이 의미가 그냥 함수형태처럼 호출할 수 있다는 것이다

  • 보통 멤버함수를 호출하려면 객체명.함수이름(인자);로 호출하는데, 함수 객체를 사용하면 객체명(인자); 로 바로 호출할 수 있게된다
    -> operator()에 정의해둔 로직이 호출되는 것

  • 일반 클래스 객체와 동일하게 서로 다른 함수 객체를 생성하면, 별개의 객체이기 때문에 멤버 변수도 서로 다른 값을 가진다

예시 코드

#include <iostream>
using namespace std;

class Adder
{
public:
    int operator()(int a, int b)
    {
        return a + b;
    }
};


int main()
{
    Adder add;

    cout << "함수객체로 호출1 : " << add(5, 4) << endl;

    cout << "함수객체로 호출2 : " << add.operator()(5, 4) << endl;

    return 0;
}



함수 객체 장점

함수 객체는 멤버 변수를 가질 수 있고, 상태 유지가 가능하다!

상태 유지 : 함수 객체를 호출할 때 멤버 변수의 값에 변동을 준다면 그 상태가 계속 유지되는 상태

-> 함수 객체 자체가 클래스에서 생성되었기 때문에 상태를 가진다 (멤버 변수 값을 변경하여 동작이 가능함)

상태를 가진다는 게, 함수 객체 자체가 클래스에서 생성된 객체니까 멤버 변수를 가지고 있는 상태를 의미


상태유지 예시

함수 객체의 경우

  • 아래의 코드는 함수 객체를 호출할때마다 멤버 변수 sum에 값이 누적된다
#include <iostream>
using namespace std;

class Adder
{
private:
    int sum;

public:
    Adder()
    {
        sum = 0;
    }

    void operator()(int value)
    {
        sum += value;
        cout << "현재 합 : " << sum << endl;
    }

    const int& Sum()
    {
        return sum;
    }
};


int main()
{
    Adder add;

    add(10);
    add(10);
    add(10);

    cout << "멤버변수 count의 값 : " << add.Sum() << endl;

    return 0;
}

출력값 :


일반 멤버 함수의 경우

근데 멤버 변수의 상태가 유지되는 것은 일반 멤버 함수도 가능한 일이다

  • 위의 예시 코드에서 ()연산자를 일반 멤버 함수로 바꾸고, 객체를 활용하여 함수를 호출하였다
    -> 보다시피 값이 누적되었고, 최종적인 멤버변수의 값도 누적된 값 그대로이다

  • 만약, 멤버 변수가 static으로 선언되어있을 경우
    -> 클래스 객체가 같은 변수를 공유하기 때문에 별개의 객체별로 다른 값을 저장할 수 없다
    -> 객체가 여러개여도 멤버 변수값이 공유되어 다 같은 멤버 변수가 된다


전역 함수의 경우

  • 전역함수에 static으로 선언한 정적변수가 있을 경우, 함수를 호출할때마다 값이 유지된다

  • 일반 변수인 경우 전역함수를 여러번 호출해도 매번 새로운 값이고 유지되지 않는다


여러 방법으로도 다 상태유지는 가능한데 왜 함수 객체를 써야하는 걸까? 공부하면서 많이 궁금했다

일반적인 클래스 객체는 데이터 저장, 멤버 함수로 기능을 수행한다

함수 객체는 주로 STL함수를 사용할 때 많이 쓴다
-> 우리는 이미정의된 클래스를 사용하여 STL함수를 사용하지만, 함수 객체가 정확히 뭔지 무엇을 뜻하는지는 알고 쓰는 것이 좋다고 생각해서 이해했다



lessgreater는 C++ STL에 포함된 함수객체(Functor)이다
-> 주로 정렬, 비교 연산에서 사용된다
(sort(), map, priority_queue)

less

오름차순 정렬을 할때 사용된다

std::less는 두 값이 '왼쪽이 오른쪽보다 작다'는 조건을 비교하는 함수 객체임

사용 방법 :less<T>()

-> 여기서 T는 템플릿으로 자료형을 지정하라 는 의미


less<T>() 사용예시

  • 오름차순으로 정렬할때 sort함수를 사용하는데, sort(시작, 끝, 함수객체); 로 선언한다

  • sort함수를 사용하기 위해서 #include <algorithm>

  • less함수를 사용하기 위해서 #include <functional>

  • sort함수를 사용할때는 less함수객체를 사용하지 않더라도 기본적으로 오름차순이다

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>  // std::less

using namespace std;

int main() 
{
    vector<int> vec = { 10, 2, 30, 4, 15 };

    // less 함수 객체를 이용한 오름차순 정렬
    sort(vec.begin(), vec.end(), less<int>());

    // 정렬된 벡터 출력
    for (int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << " ";
    }
    cout << endl;

    return 0;
}

greater

내림차순 정렬을 할때 사용된다

std::greater는 두 값이 '왼쪽이 오른쪽보다 크다'는 조건을 비교하는 함수 객체임

사용 방법 :greater<T>()


greater<T>() 사용예시

  • less와 기본적으로 다 동일하고 내림차순으로 정렬된다
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>  // std::greater

using namespace std;

int main() 
{
    vector<int> vec = { 10, 2, 30, 4, 15 };

    // greater 함수 객체를 이용한 내림차순 정렬
    sort(vec.begin(), vec.end(), greater<int>());

    // 정렬된 벡터 출력
    for (int i = 0; i < vec.size(); i++)
    {
        cout << vec[i] << " ";
    }
    cout << endl;

    return 0;
}

실제 함수 객체로 구현 less

  1. 사용자 정의 template 클래스를 하나 만들고 안에 operator()연산자를 사용하여 a < b라면 true를 반환하는 로직을 정의했다

  2. 함수 객체 less안에 이미 a < b를 반환하는 로직을 정의해두었기 때문에 sort함수 내에 사용할 경우 적용된다

아직 sort함수의 내부구조에 대해서는 다뤄보지 않았기 때문에, 정확환 과정은 모르지만
-> sort함수 내부의 두 값을 가져와서 less 객체를 호출하고, 호출된 operator가 두 값을 비교한다 라고 이해해두자

#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>  // std::greater

using namespace std;

template <typename T>
class Less
{
public:
    bool operator() (const T& a, const T& b)
    {
        return a < b;
    }
};

int main() 
{
    Less<int>less; // 함수객체 생성

    vector <int> vector = { 1, 2, 3, 4, 5 };

    sort(vector.begin(), vector.end(), less);

    for (int i = 0; i < vector.size(); i++)
    {
        cout << vector[i] << " ";
    }

    return 0;
}


사진 출처 : https://programmerpsy.tistory.com/52


  • plus<T>() & minus<T>() 예시
#include <iostream>
#include <vector>
#include <algorithm>
#include <functional>  // std::greater

using namespace std;

struct Plus
{
    int operator() (int a, int b)
    {
        return a + b;
    }
};

int main() 
{
    cout << "(일반적인 사용) 더하기 : " << plus<int>()(10, 20) << endl;

    Plus pluss;

    cout << "(함수객체 사용) 더하기 : " << pluss(10, 20) << endl;
    cout << "(명시적 호출) 더하기 : " << pluss.operator()(10, 20) << endl; // 명시적 호출

    cout << "빼기 : " << minus<int>()(20, 10);

    return 0;
}

결론

함수 객체를 사용하는 이유

다양한 STL 알고리즘에서 사용된다


📌 비교함수 복습

기준점은 무조건 앞에오는 a다.

  • a > b : 내림차순
    a가 b보다 크다면 a가 앞에온다. 즉, a > b 조건이 맞다면 a가 앞에 온다는 것

  • a < b : 오름차순
    a가 b보다 작다면 a가 앞에온다. 즉, a < b 조건이 맞다면 a가 앞에 온다는 것


🔹 비교함수 예시

bool Less(const int & a, const int & b)
{
    return a < b; // 오름차순
}

bool Greater(const int& a, const int& b)
{
    return a > b; // 내림차순
}

int main() 
{
    vector<int>v;
    
    v.push_back(10);
    v.push_back(40);
    v.push_back(30);
    v.push_back(20);
    v.push_back(50);


    sort(v.begin(), v.end(), Less);    // 오름차순

    for (int& c : v) cout << c << " "; // 10 20 30 40 50

    sort(v.begin(), v.end(), Greater); //  내림차순

    for (int& c : v) cout << c << " "; // 50 40 30 20 10
}
profile
뉴비 개발자

0개의 댓글