absl::compare — three-way 비교
#three-way comparison이 푸는 문제
C++20 이전에는 비교 가능 타입이 최소 6개의 연산자를 정의해야 했다(==, !=, <, <=, >, >=). 매번 boilerplate.
// 회피 — 6개 연산자 수동struct Point { int x, y; bool operator==(const Point& o) const { return x == o.x && y == o.y; } bool operator!=(const Point& o) const { return !(*this == o); } bool operator<(const Point& o) const { return std::tie(x, y) < std::tie(o.x, o.y); } bool operator<=(const Point& o) const { return !(o < *this); } bool operator>(const Point& o) const { return o < *this; } bool operator>=(const Point& o) const { return !(*this < o); }};C++20 operator<=>는 한 번에 처리한다.
// C++20struct Point { int x, y; auto operator<=>(const Point&) const = default;};Abseil은 C++17 이하 환경에 세 가지 ordering 카테고리를 제공해서 spaceship-스러운 디자인을 가능하게 한다(단 spaceship 자체는 컴파일러 지원이 필요해 직접 polyfill하지 않는다).
#include "absl/types/compare.h"
absl::weak_ordering wo = absl::weak_ordering::less;absl::strong_ordering so = absl::strong_ordering::equal;absl::partial_ordering po = absl::partial_ordering::unordered;#세 가지 ordering 카테고리
| 카테고리 | 의미 | 예 |
|---|---|---|
strong_ordering | 동등 = 구별 불가 | int, std::string |
weak_ordering | 동등 = 같은 동치 클래스 | 대소문자 무시 문자열 |
partial_ordering | 일부는 비교 불가 | float (NaN), 부분 순서 집합 |
strong ⊆ weak ⊆ partial 관계. strong은 weak으로, weak은 partial로 변환 가능.
#값 종류
각 카테고리는 가능한 값이 정해져 있다.
// strong_ordering: less, equal, greaterabsl::strong_ordering::less;absl::strong_ordering::equal;absl::strong_ordering::greater;
// weak_ordering: less, equivalent, greaterabsl::weak_ordering::less;absl::weak_ordering::equivalent;absl::weak_ordering::greater;
// partial_ordering: less, equivalent, greater, unorderedabsl::partial_ordering::less;absl::partial_ordering::equivalent;absl::partial_ordering::greater;absl::partial_ordering::unordered; // NaN 같은 경우#0과의 비교
<=> 결과는 0과 비교해 의미를 본다.
auto r = a <=> b;if (r < 0) std::cout << "less";else if (r == 0) std::cout << "equal/equiv";else std::cout << "greater";absl::strong_ordering/weak_ordering/partial_ordering도 동일 인터페이스.
absl::weak_ordering r = CompareCaseInsensitive("Hello", "hello");if (r == 0) { // equivalent}#비교 함수의 권장 시그니처
라이브러리 helper를 만들 때 three-way가 효율적이다(< 한 번, == 한 번 두 번 부르는 대신 한 번).
// 회피 — 두 번 비교template <typename T>int Cmp(const T& a, const T& b) { if (a < b) return -1; if (b < a) return 1; return 0;}
// Good — 한 번에 의미 추출template <typename T>absl::weak_ordering ThreeWay(const T& a, const T& b);#호환성 — std::strong_ordering으로 변환
C++20 컴파일러에서는 absl::*_ordering이 std::*_ordering의 별칭이다(C++20 이상 빌드).
// C++20 빌드static_assert(std::is_same_v<absl::strong_ordering, std::strong_ordering>);따라서 다음과 같은 자연스러운 마이그레이션이 가능.
// before — C++17 코드absl::strong_ordering Compare(const T&, const T&);
// after — C++20에서도 그대로 컴파일, std와 호환absl::strong_ordering Compare(const T&, const T&);#absl::compare가 spaceship을 구현하나?
직접 구현하지 않는다. operator<=>는 컴파일러 빌트인이라 폴리필이 불가능하다. Abseil이 제공하는 것은 결과 타입과 비교 helper뿐.
C++17 코드는 여전히 operator< 등 개별 연산자를 정의해야 한다. 다만 내부 비교 함수를 weak_ordering 반환으로 통일해 두면 C++20 마이그레이션 시 매끄럽다.
#작은 예시 — version comparison
struct Version { int major, minor, patch; std::string prerelease; // 빈 문자열이 stable
absl::weak_ordering CompareTo(const Version& o) const { // abseil은 public 3-way compare functor를 제공하지 않는다. 직접 만든다. auto cmp = [](const auto& a, const auto& b) -> absl::weak_ordering { if (a < b) return absl::weak_ordering::less; if (b < a) return absl::weak_ordering::greater; return absl::weak_ordering::equivalent; }; if (auto r = cmp(major, o.major); r != 0) return r; if (auto r = cmp(minor, o.minor); r != 0) return r; if (auto r = cmp(patch, o.patch); r != 0) return r;
// prerelease 있음 < prerelease 없음 (semver 규칙) if (prerelease.empty() != o.prerelease.empty()) { return prerelease.empty() ? absl::weak_ordering::greater : absl::weak_ordering::less; } return cmp(prerelease, o.prerelease); }
bool operator<(const Version& o) const { return CompareTo(o) < 0; } bool operator==(const Version& o) const { return CompareTo(o) == 0; } // 나머지 연산자는 < 와 ==에서 파생};#회피 패턴
// 회피 — 비교 함수가 bool 반환만bool LessVersion(const Version& a, const Version& b); // < 만 표현 가능
// Good — three-wayabsl::weak_ordering CompareVersion(const Version& a, const Version& b);// 회피 — float에 strong_orderingabsl::strong_ordering Cmp(float a, float b); // NaN 처리 모호
// Good — partial_orderingabsl::partial_ordering Cmp(float a, float b);#정리
absl::strong_ordering/weak_ordering/partial_ordering— 비교 결과 카테고리.- C++20에서
std::*_ordering의 별칭, C++17에서 polyfill. operator<=>는 컴파일러 빌트인이라 polyfill 불가 — 결과 타입만 제공.- three-way 비교는 한 번 비교로 끝 — 효율적.
- float·부분 순서는
partial_ordering, 일반적 정렬은strong_ordering.
#다음 장 예고
Part 9-08: utility — apply, in_place 등 작은 utility.
#관련 항목
- Part 5-04: btree_map — comparator 사용
- Part 9-04: absl::variant — variant 비교
- 원문 — absl::compare
Abseil Code Review · 55 of 79
- 1 Abseil Code Review — Google production-grade C++ 라이브러리 분석
- 2 Abseil 개요 — Google이 std를 보완한 이유
- 3 Abseil 설계 철학 — std 호환과 추가 기능의 균형
- 4 Abseil 빌드와 의존성 — Bazel vs CMake
- 5 Abseil LTS vs HEAD 릴리스 모델 분석
- 6 Abseil Versioning과 ABI 호환성 정책
- 7 Abseil 매크로 — ABSL_HAVE_*·ABSL_ATTRIBUTE_*
- 8 Abseil ABSL_PREDICT_TRUE/FALSE — branch hint
- 9 absl::LogSeverity — 로그 레벨 타입
- 10 Abseil type_traits — negation·conjunction·void_t
- 11 Abseil Conformance·Policy 분석
- 12 Abseil Memory utilities 분석
- 13 Abseil raw_logging — heap-free 로깅
- 14 Abseil thread_annotations — clang TSA 통합
- 15 absl::Status — exception-free error handling
- 16 absl::StatusOr<T> — 값 또는 에러
- 17 absl status_macros — ASSIGN_OR_RETURN·RETURN_IF_ERROR
- 18 absl::Status payload — 구조화된 에러 컨텍스트
- 19 absl::Status ↔ exception 변환 패턴
- 20 absl::string_view — non-owning 문자열 참조
- 21 absl::string_view 함정 — dangling·c_str·임시 객체
- 22 absl::StrCat — 가변 인자 문자열 연결과 AlphaNum
- 23 absl::StrSplit — Delimiter·Predicate·컨테이너 변환
- 24 absl::StrJoin — 컨테이너 결합과 Formatter
- 25 absl::StrFormat — type-safe printf·FormatSpec
- 26 Abseil ASCII 함수 — locale-free 분류·대소문자 변환
- 27 Abseil Escape — CEscape·HexEscape·Base64
- 28 absl::flat_hash_map — Swiss Table 기반 hash map
- 29 absl::flat_hash_set — set 버전 Swiss Table
- 30 absl::node_hash_map — stable pointer가 필요할 때
- 31 absl::btree_map — sorted·cache-friendly B-tree
- 32 absl::FixedArray — 런타임 크기 stack 배열
- 33 absl::InlinedVector — small buffer optimization
- 34 Abseil Swiss Table internals — control byte·SIMD probing
- 35 absl::Mutex — reader-writer·fairness·deadlock 검출
- 36 absl::Mutex Conditional Critical Section — Await로 cv 없애기
- 37 absl::Notification — once-only signal
- 38 absl::BlockingCounter·Barrier — 다중 thread 조율
- 39 absl::Mutex annotations — clang thread-safety로 race를 컴파일 타임에
- 40 absl::Time·Duration 분석 — 단단한 type
- 41 absl::Time Format·Parse
- 42 absl::CivilTime 분석
- 43 absl::time_zone 분석
- 44 absl::Time mocking — 테스트 친화 시간
- 45 absl::BitGen — 모던 난수 생성기
- 46 Abseil Random Distributions — Uniform·Exponential
- 47 Abseil Mocking Random — 테스트 결정성
- 48 Abseil Random Seeding·Entropy
- 49 absl::int128·uint128 분석
- 50 absl::bits — popcount·countl_zero
- 51 absl::optional vs std::optional
- 52 absl::variant 분석
- 53 absl::span 분석
- 54 absl::any 분석
- 55 absl::compare — three-way 비교
- 56 Abseil utility — apply·in_place
- 57 Abseil AbslHashValue 분석
- 58 Abseil HashState chaining
- 59 Abseil Custom hashable 구현
- 60 Abseil LOG·VLOG·CHECK 분석
- 61 Abseil LogSink 분석
- 62 Abseil LogEntry·structured logging
- 63 Abseil Stack trace·failure_signal_handler
- 64 ABSL_FLAG 정의 분석
- 65 Abseil ParseCommandLine 동작
- 66 Abseil Flag introspection·validation
- 67 Google 스타일의 Abseil 사용 패턴
- 68 Abseil 자주 보는 anti-pattern
- 69 std → absl 마이그레이션 전략
- 70 absl::Cleanup — 함수 종료 시 실행 보장
- 71 Abseil algorithm container 확장 — c_sort·c_find_if·c_count_if
- 72 absl::function_ref와 any_invocable — 함수 객체 전달의 두 축
- 73 absl::bind_front와 Overload — 함수 객체 보조 도구
- 74 absl::Cord — 분산 시스템용 대용량 문자열
- 75 absl::from_chars·SimpleAtoi — 빠른 숫자 변환
- 76 absl::Cord vs std::string — 선택 기준과 메모리 프로파일
- 77 absl::GetStackTrace와 Symbolize — crash 시 readable stack
- 78 absl::ComputeCrc32c — 하드웨어 가속 체크섬
- 79 absl::PeriodicSampler — 적응형 샘플링·jitter 회피
관련 글
Abseil utility — apply·in_place
absl::apply, in_place_t, integer_sequence — std 미도착 또는 가독성 보강 헬퍼 모음.
같은 시리즈에서 이어 읽기
absl::PeriodicSampler — 적응형 샘플링·jitter 회피
absl::profiling_internal::PeriodicSampler — sampling rate를 동적으로 조정, geometric distribution으로 jitter 회피. 메모리 할당 추적·profiling 인프라의 기반.
같은 시리즈에서 이어 읽기
absl::ComputeCrc32c — 하드웨어 가속 체크섬
absl::ComputeCrc32c — SSE4.2 CRC32, ARM CRC 명령어로 가속된 CRC32C 구현. iSCSI·Btrfs·protobuf에서 표준화된 무결성 검사.
같은 시리즈에서 이어 읽기