C ++ 20은 기본 비교, 일명 "우주선"을 도입했습니다operator<=> .이를 통해 컴파일러 생성 </ <=/ ==/ !=/ >=/ 및 / 또는 >명백한 / 순진한 (?) 구현으로 연산자 를 요청할 수 있습니다 .
auto operator<=>(const MyClass&) const = default;
...하지만 더 복잡한 상황에 맞게 사용자 정의 할 수 있습니다 (아래에서 설명). 타당성과 논의가 포함 된 언어 제안 은 여기 를 참조 하십시오 . 이 답변은 C ++ 17 및 이전 버전과 관련이 있으며 구현을 사용자 정의해야하는시기에 대한 통찰력을 제공합니다.operator<=> ... .
이전에 표준화하지 않은 것은 C ++에 약간 도움이되지 않을 수 있지만, 종종 구조체 / 클래스에는 비교 에서 제외 할 데이터 멤버 (예 : 카운터, 캐시 된 결과, 컨테이너 용량, 마지막 작업 성공 / 오류 코드, 커서)가 있습니다. 다음을 포함하되 이에 국한되지 않는 무수한 사항에 대한 결정을 내릴 수 있습니다.
- 먼저 비교할 필드, 예를 들어 특정
int구성원을 비교하면 동일하지 않은 개체의 99 %를 매우 빠르게 제거 할 수있는 반면map<string,string> 멤버는 종종 동일한 항목을 가지고 있고 비교하는 데 상대적으로 비용이 많이들 수 있습니다. 값이 런타임에로드되면 프로그래머는 다음과 같은 통찰력을 가질 수 있습니다. 컴파일러는 가능하지 않다
- 문자열 비교 : 대소 문자 구분, 공백 및 구분 기호의 동등성, 이스케이프 규칙 ...
- float / double을 비교할 때 정밀도
- NaN 부동 소수점 값이 동일한 것으로 간주되어야하는지 여부
- 포인터 또는 지적 된 데이터 비교 (후자의 경우 포인터가 배열에 대한 것인지 비교가 필요한 객체 / 바이트 수를 아는 방법)
- 정렬되지 않은 컨테이너를 비교할 때 순서가 중요한지 (예 :
vector, list), 그렇다면 비교하기 전에 제자리에서 정렬하는 것이 좋은지 비교가 완료 될 때마다 임시를 정렬하기 위해 추가 메모리를 사용하는 것이 좋은지 여부
- 현재 비교해야 할 유효한 값을 보유하고있는 배열 요소의 수 (어딘가에 크기 또는 센티넬이 있습니까?)
union비교할의 멤버
- 정규화 : 예를 들어 날짜 유형은 범위를 벗어난 날짜 또는 월을 허용 할 수 있습니다. 또는 합리적 / 분수 객체는 6/8을 가질 수 있고 다른 하나는 3 / 4ers를 가질 수 있으며 이는 성능상의 이유로 수정합니다. 별도의 정규화 단계로 느리게; 비교하기 전에 정규화를 트리거할지 여부를 결정해야 할 수 있습니다.
- 약한 포인터가 유효하지 않을 때해야 할 일
- 구현하지 않는 회원들과 기지 처리하는 방법을
operator==스스로 (하지만있을 수 있습니다 compare()또는 operator<또는 str()또는 게터를 ...)
- 다른 스레드가 업데이트하려는 데이터를 읽고 / 비교하는 동안 수행해야하는 잠금
따라서 특정 구조에 대해 비교가 의미하는 바에 대해 명시 적으로 생각할 때까지 오류가 발생하는 것이 좋습니다. 컴파일하는 대신 런타임에 의미있는 결과를 제공하지 않습니다 .
즉, bool operator==() const = default;"순진한"멤버 별 ==테스트 가 괜찮다고 결정할 때 C ++에서 말할 수 있다면 좋을 것 입니다. 동일에 대한 !=. 을 감안할 때 여러 회원 / 기지, "기본" <, <=, >, 및 >=구현은 희망하지만 보인다 - 선언의 수 있지만, 원에 의해 그룹화, 염기는 회원 전에 반드시 인 (회원 주문에 대한 명령형 충돌 주어진 무슨 일이 매우 가능성의 순서에 근거하여 계단식 의존적 사용 전 접근성, 건설 / 파괴). 보다 광범위하게 유용하게 사용하려면 C ++는 선택을 안내하는 새로운 데이터 멤버 /베이스 주석 시스템이 필요합니다.하지만 AST 기반 사용자 정의 코드 생성과 이상적으로 결합 된 표준에 포함되어 있으면 좋을 것입니다. 그것'
평등 연산자의 일반적인 구현
그럴듯한 구현
그것은의 가능성이 합리적이고 효율적으로 구현 될 것이라고 :
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.my_struct2 == rhs.my_struct2 &&
lhs.an_int == rhs.an_int;
}
이것이 필요합니다 operator==위해 MyStruct2너무.
이 구현의 의미와 대안은 아래 MyStruct1의 세부 사항에 대한 토론 제목 아래에 설명되어 있습니다.
==, <,> <= 등에 대한 일관된 접근 방식
std::tuple의 비교 연산자 를 활용 하여 자신의 클래스 인스턴스를 비교하는 것은 쉽습니다 std::tie. 원하는 비교 순서로 필드에 대한 참조 튜플을 만드는 데 사용 하면됩니다. 여기 에서 내 예를 일반화 :
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) ==
std::tie(rhs.my_struct2, rhs.an_int);
}
inline bool operator<(const MyStruct1& lhs, const MyStruct1& rhs)
{
return std::tie(lhs.my_struct2, lhs.an_int) <
std::tie(rhs.my_struct2, rhs.an_int);
}
// ...etc...
비교할 클래스를 "소유"(즉, 기업 및 타사 라이브러리가있는 요소를 편집 할 수 있음) 할 때 특히 C ++ 14가 return명령문 에서 함수 반환 유형을 추론 할 준비가되어 있으면 "를 추가하는 것이 더 좋습니다. "멤버 함수를 비교할 수있는 클래스에 연결합니다.
auto tie() const { return std::tie(my_struct1, an_int); }
그런 다음 위의 비교는 다음과 같이 단순화됩니다.
inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
return lhs.tie() == rhs.tie();
}
보다 완전한 비교 연산자 세트를 원한다면 부스트 연산자 (검색)를 제안 less_than_comparable합니다. 어떤 이유로 부적합한 경우 지원 매크로 (온라인) 아이디어가 마음에들 수도 있고 그렇지 않을 수도 있습니다 .
#define TIED_OP(STRUCT, OP, GET_FIELDS) \
inline bool operator OP(const STRUCT& lhs, const STRUCT& rhs) \
{ \
return std::tie(GET_FIELDS(lhs)) OP std::tie(GET_FIELDS(rhs)); \
}
#define TIED_COMPARISONS(STRUCT, GET_FIELDS) \
TIED_OP(STRUCT, ==, GET_FIELDS) \
TIED_OP(STRUCT, !=, GET_FIELDS) \
TIED_OP(STRUCT, <, GET_FIELDS) \
TIED_OP(STRUCT, <=, GET_FIELDS) \
TIED_OP(STRUCT, >=, GET_FIELDS) \
TIED_OP(STRUCT, >, GET_FIELDS)
... 그런 다음 사용할 수 있습니다 ...
#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)
(C ++ 14 멤버 타이 버전은 여기 )
MyStruct1의 세부 사항에 대한 토론
독립형 대 멤버를 제공하는 선택에 영향을 미칩니다 operator==()...
독립 구현
당신은 흥미로운 결정을 내릴 수 있습니다. 클래스를에서 암시 적으로 구성 할 수 있으므로 MyStruct2독립 / 비 멤버 bool operator==(const MyStruct2& lhs, const MyStruct2& rhs)함수가 지원합니다 ...
my_MyStruct2 == my_MyStruct1
... 먼저에서 임시 파일 MyStruct1을 my_myStruct2만든 다음 비교를 수행합니다. 이것은 MyStruct1::an_int생성자의 기본 매개 변수 값인 -1. an_int의 구현에 비교 를 포함하는지 여부에 따라 operator==a MyStruct1는 의 멤버와 MyStruct2동일하게 비교 되는 a와 같을 수도 있고 그렇지 않을 수도 있습니다 ! 또한 임시 생성 은 기존 멤버를 임시로 복사 하고 비교 후에 버려야하기 때문에 매우 비효율적 인 작업 일 수 있습니다 . (물론, 당신은 그 생성자를 만들 거나의 기본값을 제거함으로써 비교를위한 s의 암시 적 생성을 막을 수 있습니다.)MyStruct1my_struct_2MyStruct1my_struct2MyStruct1explicitan_int
회원 구현
당신이 암시 건설 피하려면 MyStruct1A로부터를 MyStruct2, 비교 연산자 A는 멤버 함수를합니다
struct MyStruct1
{
...
bool operator==(const MyStruct1& rhs) const
{
return tie() == rhs.tie(); // or another approach as above
}
};
메모 const만을 멤버 구현에 필요한 - - 키워드를 객체를 비교하는을 수정하지 않는 컴파일러 조언 때문에 허용 될 수 const객체.
가시적 표현 비교
원하는 유형의 비교를 얻는 가장 쉬운 방법은 다음과 같습니다.
return lhs.to_string() == rhs.to_string();
... 그것은 종종 매우 비싸다-그것들 string은 단지 버려지기 위해 고통스럽게 만들어졌습니다! 부동 소수점 값이있는 유형의 경우 표시되는 표현을 비교하면 표시된 자릿수가 비교 중에 거의 동일한 값이 동일하게 처리되는 허용 오차를 결정합니다.
struct의 s를 평등 하게 비교하고 싶은지 알고 있습니까? 그리고 당신이 간단한 방법을 원한다면,memcmp당신의 구조체가 포인터를 포함하지 않는 것은 항상 너무 길다.