std::less의 개선 (C++14)

문제

  • 기존 std::less<T>타입이 같아야만 비교 가능.

개선

  • std::less<void> 특수화를 통해 타입이 달라도 비교 가능.
  template<>
struct less<void> {
    template<typename T1, typename T2>
    constexpr auto operator()(T1&& a, T2&& b) const
        -> decltype(std::forward<T1>(a) < std::forward<T2>(b)) {
        return std::forward<T1>(a) < std::forward<T2>(b);
    }
};
  

Transparent Function (투명 함수)

  • 서로 다른 타입끼리 비교 가능하게 검색할 때 key 타입이 정확히 일치하지 않아도, 비교 가능하기만 하면 허용할 수 있게 해주는 메커니즘
  • comparator (비교 함수 객체)에 is_transparent를 추가해 타입 변환 지원.
  • SFINAE 기술

예시: set에서 intPeople 검색

  struct People {
    int id;
};

struct PeopleCompare {
    using is_transparent = int;
    
    bool operator()(const People& p1, const People& p2) const { return p1.id < p2.id; }
    bool operator()(const People& p, int id) const { return p.id < id; }
    bool operator()(int id, const People& p) const { return id < p.id; }
};
  

적용 예시

컨테이너 | comparator 기본값 | 투명 여부 std::set | std::less | ❌ std::set<Key, std::less<» | std::less<> | ✅ std::unordered_set | std::hash + std::equal_to | ❌ std::unordered_set<Key, std::hash<>, std::equal_to<» | std::hash<> + std::equal_to<> | ✅

Static operator() (C++23)

  • C++23부터 operator()가 static 멤버함수가 될 수 있음

  • 장점

    • 성능
      • 객체에 대한 정보를 전달할 필요가 없음(thiscall)
      • 어셈블리 레벨에서 보면 그냥 멤버함수는 인자가 3개이지만 static은 2개
    • 유연성
      • static 함수로 만들고 변환 연산자를 제공하면 함수 포인터로 함수 객체 가리킬 수 있음
      • 변환 연산자
        • 함수 포인터로 함수 객체의 이름 받을 수 있게 해주는

예시

  struct Plus {
    static int operator()(int a, int b) { return a + b; }
    
    using PF = int(*)(int, int);
    operator PF() const { return &Plus::operator(); }
};
  
  • 결론
    • 상태를 가지지않는 함수 객체는 static operator()를 사용하는 것이 좋음