Подтвердить что ты не робот

Могу ли я использовать operator ==, если бы я только реализовал оператор <?

Я реализовал operator< для определенного объекта. Логически, если !(a < b) и !(b < a) означает a == b.

Это выводится автоматически? Могу ли я использовать ==, если я использую только <?

4b9b3361

Ответ 1

С++ не может вывести это автоматически по нескольким причинам:

  • Для каждого отдельного типа не имеет смысла сравнивать с operator<, поэтому тип необязательно может определять operator<.
    • Это означает, что operator== не может быть автоматически определен в терминах operator<
  • operator< не требуется сравнивать свои аргументы. Программист может определять операторы для своих типов, чтобы сделать почти что угодно для своих аргументов.
    • Это означает, что ваше утверждение о !(a < b) && !(b < a), эквивалентное a == b, может не обязательно быть истинным, если предположить, что эти операторы определены.

Если вам нужна функция operator== для ваших типов, просто определите ее самостоятельно. Это не так сложно:)

// For comparing, something like this is used
bool operator==(const MyType& lhs, const MyType& rhs)
{
    // compare (or do other things!) however you want
}

// ... though it not the only thing you can do
//  - The return type can be customised
//  - ... as can both of the arguments
const MyType& operator==(int* lhs, const MyType* const rhs)
{
    return lhs;
}

Ответ 2

Он не может вывести == из <, потому что не все типы упорядочены, например std::complex. Является ли 2 + 3i > 1 + 4i или нет?

Более того, даже в типах, которые обычно упорядочены, вы все равно не можете вывести равенство из > или <, например IEEE-754 NaN

double n = std::numeric_limits<double>::quiet_NaN();

std::cout << "NaN == NaN: " << (n == n) << '\n';
std::cout << "NaN < NaN: " << (n < n) << '\n';
std::cout << "NaN > NaN: " << (n > n) << '\n';
std::cout << "NaN != NaN: " << (n != n) << '\n';

Все они вернут false, кроме последнего

Ответ 3

Нет. Этот метод хорошо работает на числовых объектах, который называется полностью заказанным. Для всех видов set/class никто не может гарантировать это отношение. Даже никто не может гарантировать, что operator < что-то сравнит.

So == - это не что иное, как ==. Вы можете реализовать == с помощью <, но это не работает для всех, и стандарты С++ не сделают этого для вас.

Ответ 4

Логически, если! (a < b) и! (b < a), это означает a == b. Вывод С++ это автоматически? Могу ли я использовать ==, если бы я только реализовал

Чтобы сформулировать то, что другие заявили в математических терминах: предположив, что у вас есть operator <, который возвращает bool и определяет строгий слабый порядок, и вы реализуете operator == как возвращающий !(a < b) && !(b < a), то этот оператор определяет эквивалентность, соответствующая данному строгому слабому порядку. Однако С++ не требует, чтобы operator < определял строгий слабый порядок, а не operator ==, чтобы определить отношение эквивалентности (хотя многие стандартные алгоритмы, такие как sort, могут неявно использовать эти операторы и требуют строгого отношения rsp..

Если вы хотите определить все другие реляционные операторы, основанные на строгом слабом порядке operator <, которые соответствуют вашему стандарту operator <, Boost.Operators могут сэкономить вам некоторую типизацию.

Потому что так легко злоупотреблять operator <, который не соответствует требованиям стандартного алгоритма, например. случайно используя его через std::sort, std::lower_bound и т.д., я рекомендую определить operator < либо как строгий слабый порядок, либо совсем не. Примером CodesInChaos является частичный порядок, который не соответствует требованию "транзитивности несравнимости" строгого слабого порядка. Поэтому я бы рекомендовал называть такое отношение другим именем, например. bool setLess(const MySet &, const MySet &).

Источники:

Ответ 5

С++ не делает этого автоматически. Для operator>, operator<= и operator>= вы можете использовать std::rel_ops; для этого требуется только operator<. Однако он не обеспечивает operator== в терминах operator<. Вы можете сделать это так:

template <class T>
bool operator==(T const& lhs, T const& rhs)
{
    return !((lhs < rhs) or (rhs < lhs));
}

Обратите внимание, что: !((lhs < rhs) or (rhs < lhs)) и !(lhs < rhs) and !(rhs < lhs) являются математически эквивалентными.

Ответ 6

Компилятор не выводит == из <.

Вы можете проверить это с помощью простого примера:

#include <iostream>

struct A {
    A(int r):i{r}{}
    int i;
};

bool operator<(A const & a1, A const& a2) {
    return a1.i < a2.i;
}

int main(int argc, char* argv[]) {
    A a1{2};
    A a2{3};
    if(a1 == a2) {
        std::cout << "equals\n";
    }
    return 0;
}

GCC дает вам эту ошибку:

main.cpp:20:11: error: no match for 'operator==' (operand types are 'A' and 'A')

     if(a1 == a2) {

Ответ 7

В std::rel_ops есть шаблоны, которые автоматически определяют отсутствующие операторы.

Он не определяет оператор равенства, основанный на меньшем операторе, как вы пожелаете.

Тем не менее это весьма полезно; если вы определяете оператор меньшего оператора и оператора равенства, у вас будут другие операторы сравнения бесплатно.

Ответ 8

Как утверждают многие, вы не можете, и компилятор не должен этого делать.

Это не означает, что не должно быть легко перейти от < до == и всего мириада.

boost:: operator пытается облегчить задачу. Используйте его и сделайте.

Если вы хотите сделать это самостоятельно, для этого потребуется лишь немного кода для повторной реализации того, что дает вам повышение:

namespace utility {
  namespace details {
    template<class...>using void_t=void;
    template<template<class...>class Z, class, class...Ts>
    struct can_apply:std::false_type{};
    template<template<class...>class Z, class...Ts>
    struct can_apply<Z, void_t<Z<Ts...>>, Ts...>:std::true_type{};
  }
  template<template<class...>class Z, class...Ts>
  using can_apply = ::utility::details::can_apply<Z,void,Ts...>;
}

namespace auto_operators {
  template<class T, class U>
  using less_r = decltype( std::declval<T const&>() < std::declval<U const&>() );
  template<class T, class U>
  using can_less = ::utility::can_apply<less_r, T, U>;

  struct order_from_less {
    template<class T, class U>
    using enabled = std::enable_if_t<
      std::is_base_of<order_from_less, T>{}
      && std::is_base_of<order_from_less, U>{}
      && can_less<T, U>{},
      bool
    >;
    template<class T, class U>
    friend enabled<U,T>
    operator>(T const& lhs, U const& rhs) {
      return rhs < lhs;
    }
    template<class T, class U>
    friend enabled<U,T>
    operator<=(T const& lhs, U const& rhs) {
      return !(lhs > rhs);
    }
    template<class T, class U>
    friend enabled<T,U>
    operator>=(T const& lhs, U const& rhs) {
      return !(lhs < rhs);
    }
  };
  struct equal_from_less:order_from_less {
    template<class T, class U>
    using enabled = std::enable_if_t<
      std::is_base_of<order_from_less, T>{}
      && std::is_base_of<order_from_less, U>{}
      && can_less<T, U>{} && can_less<U,T>{},
      bool
    >;
    template<class T, class U>
    friend enabled<U,T>
    operator==(T const& lhs, U const& rhs) {
      return !(lhs < rhs) && !(rhs < lhs);
    }
    template<class T, class U>
    friend enabled<U,T>
    operator!=(T const& lhs, U const& rhs) {
      return !(lhs==rhs);
    }
  };
}

Вышеупомянутое должно быть записано только один раз, или эквивалентная коса получена из #include boost.

Как только у вас есть boost или выше, это так же просто, как что-то вроде:

struct foo : auto_operators::equal_from_less {
  int x;
  foo( int in ):x(in) {}
  friend bool operator<( foo const& lhs, foo const& rhs ) {
    return lhs.x < rhs.x;
  }
};

и foo теперь имеют на нем все операторы упорядочения и сравнения.

int main() {
  foo one{1}, two{2};
  std::cout << (one < two) << "\n";
  std::cout << (one > two) << "\n";
  std::cout << (one == two) << "\n";
  std::cout << (one != two) << "\n";
  std::cout << (one <= two) << "\n";
  std::cout << (one >= two) << "\n";
  std::cout << (one == one) << "\n";
  std::cout << (one != one) << "\n";
  std::cout << (one <= one) << "\n";
  std::cout << (one >= one) << "\n";
}

Живой пример.

Точка всего этого состоит в том, что С++ не является, как язык, предполагать, что < означает > и >= и == все имеет смысл. Но вы можете написать библиотеку, которая позволяет вам выбрать тип с <, и добавление тривиального базового класса внезапно сделает все эти другие операции, определенные с нулевой стоимостью времени выполнения.

Ответ 9

Ответ НЕТ, вам просто нужен простой тест

struct MyType{
    int value;
};

bool operator < (MyType& a, MyType& b)
{
    return a.value < b.value;
}

int main(int argc, char* argv[])
{
    MyType a = {3};
    MyType b = {4};
    if (a == b)
        std::cout << "a==b" << std::endl;
    if (a < b)
        std::cout << "a < b" << std::endl;
}

g++ 4.8.2 жалуется:

main.cpp: В функции 'int main (int, char **):

main.cpp: 16: 11: ошибка: нет соответствия для 'operator == (типы операндов - это MyType и MyType)

Но есть что-то подобное, что работает на С++, проверьте это понятия С++: Сравнить

он говорит:

equiv (a, b), выражение, эквивалентное! comp (a, b) & &! comp (b, a)

Ответ 10

Рассмотрим следующий пример:

class point{

  unsigned int x;
  unsigned int y;

  public:
    bool operator <(const point& other){
      return (x+y) < (other.x+other.y);
    }

    bool operator == (const point& other){
      return (x==other.x) && (y==other.y);
    }
}

И тогда мы имеем:

point a{1, 2};
point b{2, 1};

! (a < b),! (b < a), но также и (a == b).

Ответ 11

В дополнение к другим ответам,

Компилятор не может даже вывести != из ==

struct MyType
{
    int value;
};

bool operator == (const MyType& a, const MyType& b)
{
    return a.value == b.value;
}

int main()
{
    MyType a = {3};
    MyType b = {4};
    if (a != b)    // (* compilation Error *) 
        std::cout << "a does not equal b" << std::endl;
}

Было бы неплохо, если бы была возможность сообщить компилятору, что остальные рациональные операторы применимы к вашему классу.

В некоторых ответах в заголовке <utility> есть что-то, что может обеспечить такую ​​функциональность. вам нужно будет добавить следующую строку в начале main:

using namespace std::rel_ops; 

Однако использование этого подхода является дорогостоящим и вызовет перегрузку неоднозначностей по всему месту, как отмечает JDługosz.

Ответ 12

Вид.
Но вам понадобится boost:: operator

Перегруженные операторы для типов классов обычно встречаются в группах. если ты может написать x + y, вы, вероятно, также захотите написать x + = y. Если вы можете написать x < y, вы также хотите, чтобы x > y, x >= y, и x <= y. Более того, если у вашего класса действительно удивительное поведение, некоторые из эти связанные операторы могут быть определены в терминах других (например, x >= y <= > ! (x < y)). Репликация этого шаблона для нескольких классов как утомительный, так и подверженный ошибкам. Шаблоны boost/operations.hpp помогают путем создания операторов для вас в области пространства имен на основе других операторов, которые вы определили в своем классе.

Ответ 13

Ответ ясный НЕТ. Нет никакого неявного способа. Классы С++ позволяют операторам перегружать. Итак, ваша идея, что логически, if !(a < b) and !(b < a) означает a == b. верно. И вы можете перегрузить операторы, как показано ниже. Например, класс Fraction:

class Fraction {
    int num;
    int denom;
    . . .
    public:
    . . .
    bool operator < (const Fraction &other) {
        if ((this->num * other.denom) < (this->denom * other.num))
            return false;
        else
            return true;
       }
       bool operator == (const Fraction &other) (
           if (!(*this < other) && !(other < *this)) {
               return true;
           else
               return false;
       }
};