많은 C ++ 표준 라이브러리 코드에서 불평등이 (! (a == b))로 테스트되는 이유는 무엇입니까?
이것은 C ++ 표준 라이브러리 remove
코드의 코드입니다. 불평등은 왜 if (!(*first == val))
대신에 시험 if (*first != val)
되는가?
template <class ForwardIterator, class T>
ForwardIterator remove (ForwardIterator first, ForwardIterator last, const T& val)
{
ForwardIterator result = first;
while (first!=last) {
if (!(*first == val)) {
*result = *first;
++result;
}
++first;
}
return result;
}
이것은 T에 대한 유일한 요구 사항은을 구현하는 것이므로 의미합니다 operator==
. T는 요구할 수 operator!=
있지만 여기서 일반적인 아이디어는 템플릿 사용자에게 가능한 한 적은 부담을 주어야하며 다른 템플릿은 필요하다는 것 operator==
입니다.
STL의 대부분의 기능은 operator<
또는 에서만 작동합니다 operator==
. 이를 위해서는 사용자가이 두 연산자 (또는 때로는 적어도 하나)를 구현하기 만하면됩니다. 예를 들어 순서를 관리 하지 않고 std::set
사용 operator<
(보다 정확하게 std::less
는 operator<
기본적으로 호출 ) operator>
합니다. remove
귀하의 예제에서 템플릿도 비슷한 경우입니다 - 그것은 단지 사용 operator==
하지 operator!=
가 있도록 operator!=
정의 할 필요가 없습니다.
이 코드는 C ++ 표준 라이브러리에서 코드를 제거합니다.
잘못된. 그것은 아니다 C ++ 표준 라이브러리 코드입니다. 그건 하나의 가능한 내부 구현 은 C ++ 표준 라이브러리의 기능. C ++ 표준은 실제 코드를 규정하지 않습니다. 함수 프로토 타입과 필요한 동작을 예측합니다.remove
remove
다른 말로하면 : 엄격한 언어의 관점에서,보고있는 코드 가 존재하지 않습니다 . 컴파일러의 표준 라이브러리 구현과 함께 제공되는 일부 헤더 파일에서 가져온 것일 수 있습니다. C ++ 표준에서는 이러한 헤더 파일 이 없어도 됩니다. 파일은 컴파일러 구현자가 한 줄의 요구 사항을 충족시키는 편리한 방법입니다 #include <algorithm>
(예 : 제작 std::remove
및 기타 기능 사용 가능).
불평등은 왜
if (!(*first == val))
대신에 시험if (*first != val)
되는가?
operator==
함수 에만 필요 하기 때문 입니다.
사용자 정의 유형의 연산자 오버로드와 관련하여 언어를 사용하면 모든 종류의 이상한 일을 할 수 있습니다. 오버로드 operator==
되었지만 오버로드 되지 않은 클래스를 만들 수 있습니다 operator!=
. 또는 더 나쁜 것은 : 과부하 operator!=
가 발생할 수는 있지만 완전히 관련이없는 일을한다는 것입니다.
이 예제를 고려하십시오.
#include <algorithm>
#include <vector>
struct Example
{
int i;
Example() : i(0) {}
bool operator==(Example const& other) const
{
return i == other.i;
}
bool operator!=(Example const& other) const
{
return i == 5; // weird, but nothing stops you
// from doing so
}
};
int main()
{
std::vector<Example> v(10);
// ...
auto it = std::remove(v.begin(), v.end(), Example());
// ...
}
를 std::remove
사용 operator!=
하면 결과가 상당히 달라집니다.
여기에 좋은 답변이 있습니다. 나는 단지 약간의 메모를 추가하고 싶었다.
모든 우수한 라이브러리와 마찬가지로 표준 라이브러리는 두 가지 매우 중요한 원칙을 염두에두고 설계되었습니다.
Put the least amount of responsibility on users of your library that you can get away with. Part of this has to do with giving them the least amount of work to do when using your interface. (like defining as few operators as you can get away with). The other part of it has to do with not surprising them or requiring them to check error codes (so keep interfaces consistent and throw exceptions from
<stdexcept>
when things go wrong).Eliminate all logical redundancy. All comparisons can be deduced merely from
operator<
, so why demand that users define others? e.g:(a > b) is equivalent to (b < a)
(a >= b) is equivalent to !(a < b)
(a == b) is equivalent to !((a < b) || (b < a))
and so on.
Of course on this note, one might ask why
unordered_map
requiresoperator==
(at least by default) rather thanoperator<
. The answer is that in a hash table the only comparison we ever require is one for equality. Thus it is more logically consistent (i.e. makes more sense to the library user) to require them to to define an equality operator. Requiring anoperator<
would be confusing because it's not immediately obvious why you'd need it.
The EqualityComparable
concept only requires that operator==
be defined.
Consequently, any function that professes to work with types satisfying EqualityComparable
cannot rely on the existence of operator!=
for objects of that type. (unless there are additional requirements that imply the existence of operator!=
).
The most promising approach is to find a method of determining if operator== can be called for a particular type, and then supporting it only when it is available; in other situations, an exception would be thrown. However, to date there is no known way to detect if an arbitrary operator expression f == g is suitably defined. The best solution known has the following undesirable qualities:
- Fails at compile-time for objects where operator== is not accessible (e.g., because it is private).
- Fails at compile-time if calling operator== is ambiguous.
- Appears to be correct if the operator== declaration is correct, even though operator== may not compile.
From Boost FAQ : source
Knowing that requiring ==
implementation is a burden, you never want to create additional burden by requiring !=
implementation as well.
For me personally it's about SOLID (object-oriented design) L part - Liskov substitution principle : “objects in a program should be replaceable with instances of their subtypes without altering the correctness of that program.”. In this case it is the operator != that i can replace with == and boolean inverse in boolean logic.
'development' 카테고리의 다른 글
웹 사이트에 해당하는 로그 파일 폴더를 찾는 방법은 무엇입니까? (0) | 2020.06.19 |
---|---|
iterator-> second는 무엇을 의미합니까? (0) | 2020.06.19 |
예약 된 작업 만들기 (0) | 2020.06.19 |
리눅스에서 디스크 활동을 표시하는 htop-like 도구 (0) | 2020.06.19 |
C #에서 Char.IsDigit ()와 Char.IsNumber ()의 차이점 (0) | 2020.06.19 |