==와! =는 상호 의존적입니까? a != b, 정의, 때문에,

나는 C ++에서 연산자 오버로딩에 대해 배우고, 나는 그것을보고 ==!=사용자 정의 형식 사용자 정의 할 수있는 몇 가지 특별한 기능은 간단하다. 그러나 내 관심사는 왜 두 개의 별도 정의가 필요한가? 나는 경우 생각 a == b사실, 다음 a != b, 정의, 때문에, 반대로 자동으로 거짓, 그리고 그 반대이며, 다른 가능성이없는 a != b것입니다 !(a == b). 그리고 이것이 사실이 아닌 상황을 상상할 수 없었습니다. 그러나 아마도 내 상상력이 제한적이거나 무언가에 대해 무지한가?

나는 다른 하나의 관점에서 하나를 정의 할 수 있다는 것을 알고 있지만 이것은 내가 요구하는 것이 아닙니다. 또한 가치 또는 정체성에 의해 객체를 비교하는 것의 차이점에 대해서도 묻지 않습니다. 또는 두 객체가 동시에 같거나 같지 않을 수 있는지 여부 (이것은 분명히 옵션이 아닙니다! 이러한 것들은 상호 배타적입니다). 내가 묻는 것은 이것입니다.

어떤 상황이 수 있는가하는 두 개의 오브젝트가 동일한 메이크업 감각을 수행되고 있지만, 그들에 대한 질문에 대한 질문 요청 하지 이해가되지 않습니다 같다고을? (사용자 관점 또는 구현 자의 관점에서)

그러한 가능성이 없다면, 왜 지구상에서 C ++가 왜이 두 연산자가 두 개의 별개의 함수로 정의되어 있습니까?



답변

당신은 할 수 없습니다 언어가 자동으로 다시 할 a != b!(a == b)할 때 a == b상 이외 반환 뭔가 bool. 그리고 그렇게하는 데는 몇 가지 이유가 있습니다.

식 작성기 객체가있을 수 있습니다. 여기서는 a == b비교를 수행하지 않으며 의도하지 않지만 단순히를 나타내는 식 노드를 작성 a == b합니다.

a == b직접 비교를 수행하지 않을 목적으로 게으른 평가가있을 수 있지만, 실제로 비교를 수행하기 위해 나중에 암시 적으로 또는 명시 적으로 lazy<bool>변환 할 수있는 종류를 반환합니다 bool. 식 작성기 개체와 결합하여 평가 전에 식을 완전히 최적화 할 수 있습니다.

당신은 몇 가지 사용자 정의 할 수 있습니다 optional<T>옵션 변수를 주어진 템플릿 클래스를 t하고 u, 허용 할 t == u만 반환하게 optional<bool>.

아마 내가 생각하지 못한 것이 더있을 것입니다. 그리고이 예제에서 작업 a == ba != b두 가지 모두 의미가 있지만, 여전히 a != b동일하지 !(a == b)않으므로 별도의 정의가 필요합니다.


답변

그러한 가능성이 없다면, 왜 지구상에서 C ++가 왜이 두 연산자가 두 개의 별개의 함수로 정의되어 있습니까?

당신은 그것들을 과부하시킬 수 있고, 그것들을 과부하시킴으로써 그들의 원래의 것과 완전히 다른 의미를 줄 수 있습니다.

예를 들어, <<원래 비트 단위의 왼쪽 시프트 연산자 인 operator는 이제 삽입 연산자처럼 일반적으로 오버로드됩니다 std::cout << something. 원래와 완전히 다른 의미입니다.

당신은 당신이 그것을 오버로드 할 때 작업자의 의미가 변화 받아 들일 경우에 따라서, 다음 연산자에 대한 의미 부여에서 사용자를 방지 할 이유가 없다 ==정확하게 아닌 부정 연산자는 !=이 혼동 될 수 있지만.


답변

그러나 내 관심사는 왜 두 개의 별도 정의가 필요한가?

두 가지를 모두 정의 할 필요는 없습니다.
상호 배타적 인 경우 std :: rel_ops를 정의 ==하고 <나란히 정의하면 간결 할 수 있습니다.

안개 cppreference :

#include <iostream>
#include <utility>

struct Foo {
    int n;
};

bool operator==(const Foo& lhs, const Foo& rhs)
{
    return lhs.n == rhs.n;
}

bool operator<(const Foo& lhs, const Foo& rhs)
{
    return lhs.n < rhs.n;
}

int main()
{
    Foo f1 = {1};
    Foo f2 = {2};
    using namespace std::rel_ops;

    //all work as you would expect
    std::cout << "not equal:     : " << (f1 != f2) << '\n';
    std::cout << "greater:       : " << (f1 > f2) << '\n';
    std::cout << "less equal:    : " << (f1 <= f2) << '\n';
    std::cout << "greater equal: : " << (f1 >= f2) << '\n';
}

두 물체가 동등하다는 질문은 이해가되지만, 동일하지 않다는 것은 이해가되지 않는 상황이 있습니까?

우리는 종종 이러한 연산자를 평등에 연결합니다.
이것이 기본 유형에서 작동하는 방식이지만, 이것이 사용자 정의 데이터 유형에서 작동하는 의무는 없습니다. 원하지 않으면 부울을 반환하지 않아도됩니다.

나는 사람들이 연산자를 기괴한 방식으로 과부하시키는 것을 보았지만 도메인 특정 응용 프로그램에 적합하다는 것을 알았습니다. 인터페이스가 상호 배타적임을 나타내는 것처럼 보이지만 저자는 특정 내부 논리를 추가 할 수 있습니다.

(사용자 관점 또는 구현 자의 관점에서)

나는 당신이 특정 예제를 원한다는 것을 알고
있으므로 다음은 내가 생각한 Catch 테스트 프레임 워크의 예 입니다.

template<typename RhsT>
ResultBuilder& operator == ( RhsT const& rhs ) {
    return captureExpression<Internal::IsEqualTo>( rhs );
}

template<typename RhsT>
ResultBuilder& operator != ( RhsT const& rhs ) {
    return captureExpression<Internal::IsNotEqualTo>( rhs );
}

이 연산자는 다른 일을하고 있으므로 한 방법을 다른 방법의! (not)로 정의하는 것은 의미가 없습니다. 이것이 이루어지는 이유는 프레임 워크가 비교를 인쇄 할 수 있기 때문입니다. 그렇게하려면 오버로드 된 연산자가 사용 된 컨텍스트를 캡처해야합니다.


답변

거기에 아주 잘 확립 된 규칙은 (a == b)하고 (a != b)있습니다 모두 거짓 반드시 반대하지. 특히, SQL에서 NULL과 비교하면 true 또는 false가 아닌 NULL이 생성됩니다.

직관적이지 않기 때문에 가능한 경우 새로운 예제를 작성하는 것은 좋지 않습니다. 그러나 기존 규칙을 모델링하려는 경우 연산자가 “정확하게”동작하도록하는 옵션을 갖는 것이 좋습니다. 문맥.


답변

나는 당신의 질문의 두 번째 부분, 즉 :

그러한 가능성이 없다면, 왜 지구상에서 C ++가 왜이 두 연산자가 두 개의 별개의 함수로 정의되어 있습니까?

개발자가 두 가지 모두에 과부하를 가할 수있게하는 이유 중 하나는 성능입니다. 당신은 모두를 구현하여 최적화 할 수 있습니다 ==!=. 그때x != y 보다 저렴할 수 있습니다 !(x == y). 일부 컴파일러는 최적화 할 수 있지만 특히 분기가 많은 복잡한 객체가있는 경우에는 그렇지 않을 수 있습니다.

심지어 개발자가 매우 심각하게 법률과 수학적 개념을 하스켈에, 하나는 여전히 과부하 허용 둘 모두 ==/=여기 (볼 수 있듯이, http://hackage.haskell.org/package/base-4.9.0.0/docs/Prelude .html # v : -61–61- ) :

$ ghci
GHCi, version 7.10.2: http://www.haskell.org/ghc/  :? for help
λ> :i Eq
class Eq a where
  (==) :: a -> a -> Bool
  (/=) :: a -> a -> Bool
        -- Defined in `GHC.Classes'

이것은 아마도 미세 최적화로 간주되지만 경우에 따라 보증 될 수 있습니다.


답변

두 물체가 동등하다는 질문은 이해가되지만, 동일하지 않다는 것은 이해가되지 않는 상황이 있습니까? (사용자 관점 또는 구현 자의 관점에서)

그건 의견입니다. 어쩌면 그렇지 않습니다. 그러나 전지구 적이 지 않은 언어 설계자들은 (적어도 그들에게는) 이해할 수있는 상황에 처한 사람들을 제한하지 않기로 결정했습니다.


답변

편집에 응답하여;

즉, 어떤 유형이 연산자를 가질 수 ==있지만 !=, 그 반대의 경우 는 그렇지 않은 경우가 있으며, 그렇게하는 것이 언제 합리적입니까?

일반적 으로 아닙니다. 말이되지 않습니다. 평등 및 관계 연산자는 일반적으로 세트로 제공됩니다. 평등이 있다면 불평등도 마찬가지입니다. 보다 작음, 다음보다 큼<= 등 유사한 방식뿐만 아니라 산술 연산자를 적용하고, 또한 일반적으로 천연 논리적 세트 들어온다.

이것은 std::rel_ops 네임 스페이스 . 동일하고 연산자보다 작은 연산자를 구현하는 경우 해당 네임 스페이스를 사용하면 원래 구현 된 연산자로 구현 된 다른 네임 스페이스를 사용할 수 있습니다.

, 하나가 즉시 다른 것을 의미하지 않거나 다른 측면에서 구현할 수없는 조건이나 상황이 있습니까? 그렇습니다 . 의심 할 여지가 거의 없지만, 있습니다. 다시 한번rel_ops고유 한 네임 스페이스 . 따라서 독립적으로 구현할 수 있도록 허용하면 언어를 활용하여 코드의 사용자 나 클라이언트에게 여전히 자연스럽고 직관적 인 방식으로 필요하거나 필요한 의미를 얻을 수 있습니다.

이미 언급 한 게으른 평가는 이에 대한 훌륭한 예입니다. 또 다른 좋은 예는 평등이나 불평등을 의미하지 않는 의미를 부여하는 것입니다. 이와 유사한 예는 비트 시프트 연산자 <<이며 >>스트림 삽입 및 추출에 사용됩니다. 비록 일반적인 분야에서 눈살을 찌푸리게 할 수도 있지만, 일부 영역의 경우에는 의미가있을 수 있습니다.