[c++] C ++에서 구조체를 비교하는 동안 == 연산자가 없습니다.

다음 구조체의 두 인스턴스를 비교하면 오류가 발생합니다.

struct MyStruct1 {
    MyStruct1(const MyStruct2 &_my_struct_2, const int _an_int = -1) :
        my_struct_2(_my_struct_2),
        an_int(_an_int)
    {}

    std::string toString() const;

    MyStruct2 my_struct_2;
    int an_int;
};

오류는 다음과 같습니다.

오류 C2678 : 바이너리 ‘==’: ‘myproj :: MyStruct1’유형의 왼쪽 피연산자를 사용하는 연산자를 찾을 수 없습니다 (또는 허용되는 변환이 없음).

왜?



답변

C ++에서 structs에는 기본적으로 생성 된 비교 연산자가 없습니다. 직접 작성해야합니다.

bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return /* your comparison code goes here */
}


답변

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

… 먼저에서 임시 파일 MyStruct1my_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은 단지 버려지기 위해 고통스럽게 만들어졌습니다! 부동 소수점 값이있는 유형의 경우 표시되는 표현을 비교하면 표시된 자릿수가 비교 중에 거의 동일한 값이 동일하게 처리되는 허용 오차를 결정합니다.


답변

operator ==대해 명시 적으로 정의해야합니다 MyStruct1.

struct MyStruct1 {
  bool operator == (const MyStruct1 &rhs) const
  { /* your logic for comparision between "*this" and "rhs" */ }
};

이제 == 비교는 이러한 객체 2 개에 대해 합법적입니다.


답변

C ++ 20에서 시작, 기본 비교 연산자 (의 전체 세트를 추가 할 수 있어야한다 ==, <=선언하여 클래스 등) 기본 세 방향 비교 연산자를 다음과 같이 ( “우주선”연산자) :

struct Point {
    int x;
    int y;
    auto operator<=>(const Point&) const = default;
};

호환 C ++ 20 컴파일러를 사용하면 MyStruct2의 정의가 호환된다는 가정하에 MyStruct1 및 MyStruct2에 해당 행을 추가하는 것만으로 동등성 비교를 허용 할 수 있습니다.


답변

C 또는 C ++의 구조체에서는 비교가 작동하지 않습니다. 대신 필드로 비교하십시오.


답변

기본적으로 구조체에는 ==연산자 가 없습니다 . 자체 구현을 작성해야합니다.

bool MyStruct1::operator==(const MyStruct1 &other) const {
    ...  // Compare the values, and return a bool result.
  }


답변

기본적으로 == 연산자는 기본 요소에 대해서만 작동합니다. 코드가 작동하도록하려면 구조체에 대한 == 연산자를 오버로드해야합니다.