우리는 최소치와 최대치를 정확하게 계산했습니까?

본문의 영감은 월트 E 브라운이 있는 데서 비롯되었다.
월터는 이러한 알고리즘의 몇 가지 문제를 제기했다. 서로 다른 유형의 문제부터 파라미터를 어떻게 효과적으로 전달하는지에 이르기까지. 그러나 나는 가능한 문제 하나만 주목하고 싶다.minmax의C++20 스타일의 간단한 실현을 살펴보자.
auto min(auto left, auto right) {
  return left < right ? left : right;
}

auto max(auto left, auto right) {
  return right < left ? left : right;
}
그게 무슨 문제야?
만약 left == right에 무슨 일이 일어났다면?
왼쪽과 오른쪽이 같을 때 minmax 는 같은 값을 되돌려줍니다.즉right.
그런데 이게 맞는 건가요?
월트의 말에 의하면 이것은 옳지 않다고 한다.그는 자신의 의견을 제시했지만 2014년 위원회에서 이 의견들이 흥미롭지 않다고 느꼈다.
그들은 틀림없이 매우 재미있을 거야, 여기서 토론할 수 있어.나는 그가 우리가 생각하지 못할 요점을 제시했다고 생각한다.
어떤 사람들은 그의 생각을 반대한다. 왜냐하면 어느 것으로 돌아가는 것이 중요하지 않기 때문이다. 왜냐하면 ifleft == right의 값은 구분할 수 없기 때문이다.
사실은 반드시 이와 같지 않다.
그는 학생반의 예를 들었다.
struct Student {
  std::string name;
  int id;
  inline static int registrar = 0;
  Student(const std::string& iName):
    name(iName), id(registrar++) {}

  friend bool operator<(const Student& lhs,
                        const Student& rhs) {
    return lhs.name < rhs.name;
  }
};
이런 상황에서 우리는 두 학생이 같은 이름을 가지고 있다면, 이것은 불가능한 것이 아니라, 그들을 대표하는 대상이 구분할 수 없는 것이 아니라는 것을 관찰할 수 있다.그것들은 확실히 다르다ids.
그러나 월터 공유의 실현에 따라minmax는 모두 되돌아온다right.
만약 우리가 이러고 싶지 않다면, 우리는 서로 다른 방식으로 비교 연산자를 실현해야 한다고 말할 수 있다.사실 우리는 Student::id를 비교 연산자의 일부분으로 만들어야 이 문제가 없을 것이다.
나는 만약 우리가 이러한 논리 연산자를 필요로 하고, 두 대상이 구분할 수 없는 것이 아니라 서로 같게 계산될 수 있다고 걱정한다면, 우리는 논리 연산자를 수정해야 한다고 느낀다.
C++20부터, 우리는spaceship 조작부호를 사용하여 모든 비교 조작부호를 자동으로 정의할 수 있습니다.Student클래스에서는 다음과 같이 표시됩니다.
auto operator<=>(const Student&) const = default;
컴파일러가 조작부호를 생성할 수 있다면, '왼쪽에서 오른쪽까지의 모든 기본 클래스와 클래스의 모든 비정상적인 구성원의 성명 순서' 를 고려할 것입니다.
이것은 고려할 것을 의미한다Student::id. 따라서 구분할 수 없는 두 개의 대상이 있어야 하며, 각 필드에 두 개의 값이 같은 대상이 있어야 한다.그럼 어느 쪽이 반송되는지는 정말 중요하지 않아요.
너는 논리적으로 말하자면, 우리는 모든 상황에서 이렇게 할 수 없다고 말할 수 있다.너는 옳을 수도 있고, 너는 이런 사례를 제기할 수도 있지만, 나는 이것이 주요 원인이라고 생각하지만, 월트의 불평은 고려되지 않았다.
아니면 그들인가?
어디 보자the MSVCC implementation.
이곳은 간략한 발췌문이다.
template <class _Ty>
_NODISCARD _Post_equal_to_(_Left < _Right ? _Right : _Left) constexpr const _Ty& //
    (max) (const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Left < _Right)) /* strengthened */ {
    // return larger of _Left and _Right
    return _Left < _Right ? _Right : _Left;
}

template <class _Ty>
_NODISCARD _Post_equal_to_(_Right < _Left ? _Right : _Left) constexpr const _Ty& //
    (min) (const _Ty& _Left, const _Ty& _Right) noexcept(noexcept(_Right < _Left)) /* strengthened */ {
    // return smaller of _Left and _Right
    return _Right < _Left ? _Right : _Left;
}
_Left == _Right라면 max귀환_Left하고 min도 귀환_Left한다.
우리도 보자clang:
template <class _Tp, class _Compare>
_LIBCPP_NODISCARD_EXT inline
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const _Tp&
min(const _Tp& __a, const _Tp& __b, _Compare __comp)
{
    return __comp(__b, __a) ? __b : __a;
}


template <class _Tp, class _Compare>
_LIBCPP_NODISCARD_EXT inline
_LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR_AFTER_CXX11
const _Tp&
max(const _Tp& __a, const _Tp& __b, _Compare __comp)
{
    return __comp(__a, __b) ? __b : __a;
}
본질적으로 같지만 이 예에서 원소가 같을 때 되돌아오기__a는 MS에서 _Left라고 부른다.
따라서,clang과 MSVCC에 대해 입력이 같으면 minmax의 반환값은 같다.유일한 차이점은 첫 번째 입력을 되돌려 주고 두 번째 입력을 되돌려 주는 것이다.Gcc의 동작은 첫 번째 입력, 즉 왼쪽 입력을 되돌려 주는 딩동 소리와 유사하다.
마이크로소프트가 다른 가치관을 선택한 이유가 무엇인지 궁금하다.
하지만 둘 다 이상한 사실을 바꿀 수는 없다.월터가 위원회에서 이 점을 제기했기 때문에 다른 사람들도 이를 구멍이라고 부른다.
만약 정말로 이것에 대해 곤란을 느끼고 min이 첫 번째 항목, max가 두 번째 항목으로 되돌아오기를 원한다면 std::minmax 을 사용할 수 있습니다. 왜냐하면 C++11이기 때문입니다.
그것은 두 개의 요소가 필요하거나 항목 목록이 필요하지만, 우리의 예에서 두 개의 항목만 흥미롭다.std::minmax 한 쌍을 되돌려줍니다. 첫 번째 항목은 최소 원소에 대한 상수 인용이고, 두 번째 항목은 최대 값입니다. 두 번째 입력이 같으면 첫 번째 입력이고, 두 번째 입력은 최대 값입니다.
네, 이것은 사용minmax를 모델링할 수 없음minmax을 의미합니다.
적어도 우리는 해결 방법이 있다.

결론
, Walter E Brown은 std::minstd::max의 두 입력이 같으면 같은 값을 되돌려 주는 것이 정확하지 않다는 그의 의견에 동의했다.
만약 이것이 너에게 매우 중요하다면, 너는 다른 해결 방법이 있다.원하는 방식으로 수동으로 minmax를 수행할 수 있습니다.minmax를 사용하거나 두 값을 같을 때 구분할 수 없는 비교 연산자를 사용할 수 있습니다.
만약 당신이 코드에서 이 문제를 만났다면 저에게 알려 주세요.

더욱 깊이 연락하다
만약 당신이 이 문장을 좋아한다면,
  • like버튼을 클릭하면,

  • subscribe to my newsletter
  • 계속 연결합시다!
  • 좋은 웹페이지 즐겨찾기