Namespaces
Variants

Default comparisons (since C++20)

From cppreference.net
C++ language
General topics
Flow control
Conditional execution statements
Iteration statements (loops)
Jump statements
Functions
Function declaration
Lambda function expression
inline specifier
Dynamic exception specifications ( until C++17* )
noexcept specifier (C++11)
Exceptions
Namespaces
Types
Specifiers
constexpr (C++11)
consteval (C++20)
constinit (C++20)
Storage duration specifiers
Initialization
Expressions
Alternative representations
Literals
Boolean - Integer - Floating-point
Character - String - nullptr (C++11)
User-defined (C++11)
Utilities
Attributes (C++11)
Types
typedef declaration
Type alias declaration (C++11)
Casts
Memory allocation
Classes
Class-specific function properties
Special member functions
Templates
Miscellaneous

비교 연산자 함수를 명시적으로 기본값으로 설정하여 컴파일러가 클래스에 대한 해당 기본 비교를 생성하도록 요청할 수 있습니다.

목차

정의

디폴트 비교 연산자 함수 는 다음 모든 조건을 만족하는 비템플릿 비교 연산자 함수입니다(즉 <=> , == , != , < , > , <= , 또는 >= ):

이러한 비교 연산자 함수를 클래스 C 에 대한 기본 비교 연산자 함수 라고 합니다.

struct X
{
    bool operator==(const X&) const = default; // 정상
    bool operator==(const X&) = default;       // 오류: 암시적 객체
                                               //        매개변수 타입은 X&
    bool operator==(this X, X) = default;      // 정상
};
struct Y
{
    friend bool operator==(Y, Y) = default;        // 정상
    friend bool operator==(Y, const Y&) = default; // 오류: 서로 다른 매개변수 타입
};
bool operator==(const Y&, const Y&) = default;     // 오류: Y의 friend가 아님

비교 연산자 함수의 암시적 정의에서의 이름 조회와 접근 검사는 해당 함수 본문과 동등한 컨텍스트에서 수행됩니다. 클래스 내에서 기본값으로 정의된 비교 연산자 함수의 선언은 해당 함수의 첫 번째 선언이어야 합니다.

기본 비교 순서

주어진 클래스 C 에 대해, 서브오브젝트 목록은 다음과 같은 서브오브젝트들로 순서대로 구성됩니다:

  • C 의 직접 기본 클래스 서브오브젝트를 선언 순서대로.
  • C 의 비정적 데이터 멤버 를 선언 순서대로.
  • 어떤 멤버 하위 객체가 배열 타입인 경우, 해당 배열의 요소들을 오름차순 인덱스 순서로 확장합니다. 이 확장은 재귀적으로 수행됩니다: 배열 타입의 배열 요소들은 더 이상 배열 타입의 하위 객체가 없을 때까지 다시 확장됩니다.

임의의 객체 x 가 타입 C 인 경우, 다음 설명에서:

struct S {};
struct T : S
{
    int arr[2][2];
} t;
// "t"의 서브오브젝트 목록은 다음과 같이 5개의 서브오브젝트로 순서대로 구성됩니다:
// (S)t → t[0][0] → t[0][1] → t[1][0] → t[1][1]

3항 비교

클래스 타입에 대한 operator <=> 는 어떤 반환 타입으로도 기본 정의될 수 있습니다.

비교 범주 유형

비교 범주 유형은 세 가지가 있습니다:

타입 동등한 값들은.. 비교 불가능한 값들은..
std::strong_ordering 구분 불가능함 허용되지 않음
std::weak_ordering 구분 가능함 허용되지 않음
std::partial_ordering 구분 가능함 허용됨

합성된 삼중 비교

T 타입의 합성된 삼중 비교 는 동일한 타입의 glvalue a b 사이에서 다음과 같이 정의됩니다:

  • a <=> b 에 대한 오버로드 해결이 사용 가능한 후보를 산출하고, static_cast 를 사용하여 T 로 명시적으로 변환될 수 있는 경우, 합성된 비교는 static_cast < T > ( a <=> b ) 입니다.
  • 그렇지 않고 다음 조건 중 하나라도 충족되는 경우, 합성된 비교는 정의되지 않습니다:
  • a <=> b 에 대한 오버로드 해결이 적어도 하나의 유효한 후보를 찾습니다.
  • T 는 비교 범주 타입이 아닙니다.
  • a == b 에 대한 오버로드 해결이 사용 가능한 후보를 결과로 내지 않습니다.
  • a < b 에 대한 오버로드 해결이 사용 가능한 후보를 결과로 내지 않습니다.
a == b ? std::strong_ordering::equal :
a < b  ? std::strong_ordering::less :
         std::strong_ordering::greater
a == b ? std::weak_ordering::equivalent :
a < b  ? std::weak_ordering::less :
         std::weak_ordering::greater
a == b ? std::partial_ordering::equivalent :
a < b  ? std::partial_ordering::less :
b < a  ? std::partial_ordering::greater : 
         std::partial_ordering::unordered

플레이스홀더 반환 타입

클래스 타입 C 의 기본화된 삼중 비교 연산자 함수( operator <=> )의 선언된 반환 타입이 auto 인 경우, 반환 타입은 타입 C 의 객체 x 의 해당 하위 객체들 간의 삼중 비교 연산 결과 타입들로부터 추론됩니다.

각 하위 객체 x_i 에 대해 (확장된) 하위 객체 목록 내에서 x 의:

  1. x_i <=> x_i 에 대해 오버로드 해결을 수행합니다. 오버로드 해결이 사용 가능한 후보를 생성하지 않으면, 기본 제공 operator <=> 는 삭제된 것으로 정의됩니다.
  2. x_i <=> x_i 의 타입에서 cv 한정자를 제거한 버전을 R_i 로 표기합니다. 만약 R_i 가 비교 범주 타입이 아니면, 기본 제공 operator <=> 는 삭제된 것으로 정의됩니다.

기본값으로 정의된 operator <=> 가 삭제된 것으로 정의되지 않으면, 그 반환 타입은 std:: common_comparison_category_t < R_1, R_2, ..., R_n > 로 추론됩니다.

Non-placeholder 반환 타입

기본 설정된 operator <=> 의 선언된 반환 타입이 auto 가 아닌 경우, 이는 어떠한 placeholder type (예: decltype ( auto ) )도 포함할 수 없습니다.

(확장된) 서브오브젝트 목록에 x_i 가 존재하고, 선언된 반환 타입의 합성된 3-way 비교 x_i x_i 사이에 정의되지 않는다면, 기본 정의된 operator <=> 는 삭제된 것으로 정의됩니다.

비교 결과

기본 설정된 operator <=> 의 매개변수를 x y 라 하고, x y 의 (확장된) 서브객체 목록에 있는 각 서브객체를 각각 x_i y_i 로 표기한다. x y 사이의 기본 삼중 비교는 대응하는 서브객체 x_i y_i i 가 증가하는 순서로 비교하여 수행된다.

R 을 (추론된) 반환 타입이라고 하면, x_i y_i 사이의 비교 결과는 x_i y_i 사이의 타입 R 의 합성된 삼중 비교 결과입니다.

  • 기본적인 3방향 비교에서 x y 사이의 부분 객체별 비교 시, x_i y_i 의 비교 결과 v_i v_i ! = 0 bool 로 문맥 변환했을 때 true 를 반환하는 경우, 반환값은 v_i 의 복사본입니다(나머지 부분 객체들은 비교되지 않습니다).
  • 그렇지 않은 경우, 반환값은 static_cast < R > ( std :: strong_ordering :: equal ) 입니다.
#include <compare>
#include <iostream>
#include <set>
struct Point
{
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
    /* 비교 함수가 아닌 다른 함수들 */
};
int main()
{
    Point pt1{1, 1}, pt2{1, 2};
    std::set<Point> s; // OK
    s.insert(pt1);     // OK
    // 양방향 비교 연산자 함수들은 명시적으로 정의될 필요가 없음:
    // operator==는 암시적으로 선언됨 (아래 참조)
    // 다른 후보들의 오버로드 해석은 재작성된 후보들을 선택함
    std::cout << std::boolalpha
        << (pt1 == pt2) << ' '  // false
        << (pt1 != pt2) << ' '  // true
        << (pt1 <  pt2) << ' '  // true
        << (pt1 <= pt2) << ' '  // true
        << (pt1 >  pt2) << ' '  // false
        << (pt1 >= pt2) << ' '; // false
}

동등성 비교

명시적 선언

클래스 타입에 대한 operator == 는 반환 타입이 bool 인 기본 정의로 선언될 수 있습니다.

클래스 C 와 해당 타입의 객체 x 가 주어졌을 때, x 의 (확장된) 서브객체 목록에 있는 서브객체 x_i 에 대해 x_i == x_i 의 오버로드 해결이 사용 가능한 후보를 결과로 내지 않으면, 기본 제공되는 operator == 는 삭제된 것으로 정의됩니다.

기본 설정된 operator == 의 매개변수인 x y 가 있을 때, (확장된) 서브객체 목록에 있는 각 서브객체를 각각 x_i y_i 로 표기합니다. x y 사이의 기본 동등 비교는 대응하는 서브객체 x_i y_i i 가 증가하는 순서로 비교하여 수행됩니다.

x_i y_i 의 비교 결과는 x_i == y_i 의 결과입니다.

  • 기본 동등 비교에서 x y 사이의 부분 객체 단위 비교 시, x_i y_i 의 비교 결과 v_i bool 로 문맥적 변환했을 때 false 가 생성되면, 반환 값은 false 가 됩니다(나머지 부분 객체는 비교되지 않음).
  • 그렇지 않으면 반환 값은 true 입니다.
#include <iostream>
struct Point
{
    int x;
    int y;
    bool operator==(const Point&) const = default;
    /* 비교 함수가 아닌 다른 함수들 */
};
int main()
{
    Point pt1{3, 5}, pt2{2, 5};
    std::cout << std::boolalpha
        << (pt1 != pt2) << '\n'  // true
        << (pt1 == pt1) << '\n'; // true
    struct [[maybe_unused]] { int x{}, y{}; } p, q;
    // if (p == q) {} // 오류: operator==가 정의되지 않음
}

암시적 선언

클래스 C operator == 라는 이름의 멤버나 friend를 명시적으로 선언하지 않는 경우, 기본 설정(defaulted)으로 정의된 각 operator <=> 에 대해 == 연산자 함수가 암시적으로 선언됩니다. 각 암시적으로 선언된 operator == 는 해당 기본 설정 operator <=> 와 동일한 접근 권한과 함수 정의 를 가지며 동일한 클래스 범위 에 존재하며, 다음과 같은 변경 사항이 적용됩니다:

  • 선언자 식별자가 operator == 로 대체됩니다.
  • 반환 타입이 bool 로 대체됩니다.
template<typename T>
struct X
{
    friend constexpr std::partial_ordering operator<=>(X, X)
        requires (sizeof(T) != 1) = default;
    // 암시적으로 선언: friend constexpr bool operator==(X, X)
    //                          requires (sizeof(T) != 1) = default;
    [[nodiscard]] virtual std::strong_ordering operator<=>(const X&) const = default;
    // 암시적으로 선언: [[nodiscard]] virtual bool
    //                          operator==(const X&) const = default;
};

보조 비교

클래스 타입에 대한 보조 비교 연산자 함수( != , < , > , <= , 또는 >= )는 반환 타입 bool 으로 기본 정의될 수 있습니다.

다섯 가지 보조 비교 연산자 중 하나인 @ 에 대해, 각 기본 제공 operator@ 는 매개변수 x y 를 가지며, 삭제된 것으로 정의되는지 여부를 결정하기 위해 최대 두 번의 오버로드 해결이 수행됩니다(기본 제공 operator@ 는 후보로 고려하지 않음).

  • 첫 번째 오버로드 해결은 x @ y 에 대해 수행됩니다. 오버로드 해결이 사용 가능한 후보를 생성하지 않거나 선택된 후보가 재작성된 후보 가 아닌 경우, 기본 제공 operator@ 는 삭제된 것으로 정의됩니다. 이러한 경우에는 두 번째 오버로드 해결이 수행되지 않습니다.
  • 두 번째 오버로드 해결은 x @ y 의 선택된 재작성된 후보에 대해 수행됩니다. 오버로드 해결이 사용 가능한 후보를 생성하지 않는 경우, 기본 제공 operator@ 는 삭제된 것으로 정의됩니다.

만약 x @ y 가 암시적으로 bool 으로 변환될 수 없다면, 기본 제공되는 operator@ 는 삭제된 것으로 정의됩니다.

기본으로 제공되는 operator@ 가 삭제된 것으로 정의되지 않으면, x @ y 를 반환합니다.

struct HasNoRelational {};
struct C
{
    friend HasNoRelational operator<=>(const C&, const C&);
    bool operator<(const C&) const = default; // OK, 함수가 기본값으로 설정됨
};

키워드

default

결함 보고서

다음의 동작 변경 결함 보고서들은 이전에 발표된 C++ 표준에 소급 적용되었습니다.

DR 적용 대상 게시된 동작 올바른 동작
CWG 2539 C++20 합성된 3방향 비교가 명시적 변환이 불가능한 경우에도
static_cast 를 선택함
해당 경우
static_cast 를 선택하지 않음
CWG 2546 C++20 기본 제공된 보조 operator@
x @ y 의 오버로드 해결이
사용 불가능한 재작성 후보를 선택할 경우
삭제된 것으로 정의되지 않음
해당 경우
삭제된 것으로 정의됨
CWG 2547 C++20 비클래스에 대한 비교 연산자 함수의
기본 제공 가능 여부가 불명확했음
기본 제공할 수 없음
CWG 2568 C++20 비교 연산자 함수의 암시적 정의가
멤버 접근 규칙을 위반할 수 있었음
해당 함수 본문과 동등한
컨텍스트에서 접근 검사가
수행됨

참고 항목