Programing

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

crosscheck 2020. 9. 9. 07:33
반응형

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


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

struct MyStruct1 {
    Position(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 */
}

다른 사람들이 말했듯이 비교 기능을 직접 구현해야합니다.

명백한 / naive (?) 구현을 생성하도록 컴파일러에 요청하는 제안 된 방법이 있습니다 . 여기를 참조 하십시오 .

이미 표준화하지 않은 것은 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...

When you "own" (i.e. can edit, a factor with corporate and 3rd party libs) the class you want to compare, and especially with C++14's preparedness to deduce function return type from the return statement, it's often nicer to add a "tie" member function to the class you want to be able to compare:

auto tie() const { return std::tie(my_struct1, an_int); }

Then the comparisons above simplify to:

inline bool operator==(const MyStruct1& lhs, const MyStruct1& rhs)
{
    return lhs.tie() == rhs.tie();
}

If you want a fuller set of comparison operators, I suggest boost operators (search for less_than_comparable). If it's unsuitable for some reason, you may or may not like the idea of support macros (online):

#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)

...that can then be used a la...

#define MY_STRUCT_FIELDS(X) X.my_struct2, X.an_int
TIED_COMPARISONS(MyStruct1, MY_STRUCT_FIELDS)

(C++14 member-tie version here)

Discussion of specifics of your MyStruct1

There are implications to the choice to provide a free-standing versus member operator==()...

Freestanding implementation

You have an interesting decision to make. As your class can be implicitly constructed from a MyStruct2, a free-standing / non-member bool operator==(const MyStruct2& lhs, const MyStruct2& rhs) function would support...

my_MyStruct2 == my_MyStruct1

...by first creating a temporary MyStruct1 from my_myStruct2, then doing the comparison. This would definitely leave MyStruct1::an_int set to the constructor's default parameter value of -1. Depending on whether you include an_int comparison in the implementation of your operator==, a MyStruct1 might or might not compare equal to a MyStruct2 that itself compares equal to the MyStruct1's my_struct_2 member! Further, creating a temporary MyStruct1 can be a very inefficient operation, as it involves copying the existing my_struct2 member to a temporary, only to throw it away after the comparison. (Of course, you could prevent this implicit construction of MyStruct1s for comparison by making that constructor explicit or removing the default value for an_int.)

Member implementation

If you want to avoid implicit construction of a MyStruct1 from a MyStruct2, make the comparison operator a member function:

struct MyStruct1
{
    ...
    bool operator==(const MyStruct1& rhs) const
    {
        return tie() == rhs.tie(); // or another approach as above
    }
};

Note the const keyword - only needed for the member implementation - advises the compiler that comparing objects doesn't modify them, so can be allowed on const objects.

Comparing the visible representations

Sometimes the easiest way to get the kind of comparison you want can be...

    return lhs.to_string() == rhs.to_string();

...which is often very expensive too - those strings painfully created just to be thrown away! For types with floating point values, comparing visible representations means the number of displayed digits determines the tolerance within which nearly-equal values are treated as equal during comparison.


You need to explicitly define operator == for MyStruct1.

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

Now the == comparison is legal for 2 such objects.


Starting in C++20, it should be possible to add a full set of default comparison operators (==, <=, etc.) to a class by declaring a default three-way comparison operator ("spaceship" operator), like this:

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

With a compliant C++20 compiler, adding that line to MyStruct1 and MyStruct2 may be enough to allow equality comparisons, assuming the definition of MyStruct2 is compatible.


Comparison doesn't work on structs in C or C++. Compare by fields instead.


By default structs do not have a == operator. You'll have to write your own implementation:

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

Out of the box, the == operator only works for primitives. To get your code to work, you need to overload the == operator for your struct.


Because you did not write a comparison operator for your struct. The compiler does not generate it for you, so if you want comparison, you have to write it yourself.

참고URL : https://stackoverflow.com/questions/5740310/no-operator-found-while-comparing-structs-in-c

반응형