==와! =는 상호 의존적입니까?
나는 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 == b
과 a != 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)
. 일부 컴파일러는 최적화 할 수 있지만 특히 분기가 많은 복잡한 객체가있는 경우에는 그렇지 않을 수 있습니다.
개발자가 법과 수학 개념을 매우 중요하게 생각하는 Haskell에서도 여전히 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
고유 한 네임 스페이스 로 증명 된 것처럼 다시 . 따라서 독립적으로 구현할 수 있도록 허용하면 언어를 활용하여 코드의 사용자 나 클라이언트에게 여전히 자연스럽고 직관적 인 방식으로 필요하거나 필요한 의미를 얻을 수 있습니다.
이미 언급 한 게으른 평가는 이에 대한 훌륭한 예입니다. 또 다른 좋은 예는 평등이나 불평등을 의미하지 않는 의미를 부여하는 것입니다. 이와 유사한 예는 비트 시프트 연산자 <<
이며 >>
스트림 삽입 및 추출에 사용됩니다. 비록 일반적인 분야에서 눈살을 찌푸리게 할 수도 있지만, 일부 영역의 경우에는 의미가있을 수 있습니다.
는 IF ==
및 !=
연산자는 실제로 것과 같은 방식으로 평등, 의미하지는 않습니다 <<
및 >>
스트림 연산자 비트 시프트 의미하는 것은 아닙니다합니다. 기호가 다른 개념을 의미하는 것처럼 취급하면 상호 배타적 일 필요는 없습니다.
평등의 관점에서, 유스 케이스가 객체를 비교할 수없는 것으로 취급하여 모든 비교가 거짓을 리턴하도록 (또는 연산자가 부울을 리턴하지 않는 경우 비교할 수없는 결과 유형) 처리해야하는 경우 이치에 맞을 수 있습니다. 이것이 필요한 특정 상황을 생각할 수는 없지만 그것이 합리적이라는 것을 알 수있었습니다.
큰 힘으로 책임감있게 또는 최소한 정말 좋은 스타일 가이드를 얻습니다.
==
그리고 !=
당신이 원하는대로 도대체을 수행하는 오버로드 할 수 있습니다. 축복이자 저주입니다. 을 !=
의미하는 보장은 없습니다 !(a==b)
.
enum BoolPlus {
kFalse = 0,
kTrue = 1,
kFileNotFound = -1
}
BoolPlus operator==(File& other);
BoolPlus operator!=(File& other);
이 연산자 오버로드를 정당화 할 수는 없지만 위의 예 operator!=
에서는의 "반대" 로 정의 할 수 없습니다 operator==
.
결국, 당신이 그 운영자로 확인하는 것은 표현이다 a == b
또는 a != b
부울 값을 반환 (IS true
또는 false
). 이 표현식은 비교 후 상호 배타적이지 않고 비교 후 부울 값을 반환합니다.
[..] 왜 두 개의 별도 정의가 필요합니까?
고려해야 할 사항 중 하나는 다른 연산자의 부정을 사용하는 것보다 이러한 연산자 중 하나를보다 효율적으로 구현할 가능성이 있다는 것입니다.
(여기서 제 예제는 쓰레기 였지만 요점은 여전히 그렇습니다. 예를 들어 블룸 필터를 생각해보십시오 . 세트에 없는 경우 빠른 테스트를 허용 하지만 내부에있는 경우 테스트하는 데 더 많은 시간이 걸릴 수 있습니다.)
정의상 [..]
a != b
은!(a == b)
입니다.
그리고 그것을 유지하는 것은 프로그래머로서의 책임입니다. 아마도 테스트를 작성하는 것이 좋습니다.
운영자의 동작을 사용자 정의하여 원하는대로 수행 할 수 있습니다.
당신은 물건을 사용자 정의 할 수 있습니다. 예를 들어 클래스를 사용자 정의 할 수 있습니다. 이 클래스의 객체는 특정 속성을 확인하여 비교할 수 있습니다. 이것이 사실임을 알면 전체 객체에서 모든 단일 속성의 모든 단일 비트를 확인하는 대신 최소 사항 만 확인하는 특정 코드를 작성할 수 있습니다.
더 빠르지는 않지만 무언가가 같은 것을 알 수있는 것보다 빠르지 않다는 것을 알 수있는 경우를 상상해보십시오. 물론, 무언가가 같은지 다른지를 알아 낸 후에는 약간만 뒤집으면서 그 반대를 알 수 있습니다. 그러나 해당 비트를 뒤집는 것은 추가 작업입니다. 경우에 따라 코드가 많이 다시 실행될 때 한 번의 작업 (다수로 곱함)을 저장하면 전체 속도가 증가 할 수 있습니다. 예를 들어 메가 픽셀 화면의 픽셀 당 하나의 작업을 저장하면 백만 개의 작업 만 저장 한 것입니다. 초당 60 개의 화면을 곱하면 더 많은 작업이 저장됩니다.
hvd의 답변 은 몇 가지 추가 예를 제공합니다.
그렇습니다. 하나는 "동등"을 의미하고 다른 하나는 "비등가"를 의미하며이 용어는 상호 배타적입니다. 이 연산자에 대한 다른 의미는 혼동되므로 반드시 피해야합니다.
어쩌면 uncomparable 규칙 a != b
이었다 허위 하고 a == b
있었다 거짓 무 상태 비트있다.
if( !(a == b || a != b) ){
// Stateless
}
참고 URL : https://stackoverflow.com/questions/37800001/are-and-mutually-dependent
'IT' 카테고리의 다른 글
널 입력 가능하도록 열 변경 (0) | 2020.03.18 |
---|---|
img src SVG 채우기 색상 변경 (0) | 2020.03.18 |
SQL Server에서 '설명 테이블'과 동일한 기능은 무엇입니까? (0) | 2020.03.18 |
자식 : 분기를 전환하고 커밋하지 않고 변경 사항을 무시하십시오. (0) | 2020.03.18 |
WebSockets 프로토콜과 HTTP (0) | 2020.03.18 |