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

Определение объекта, который действует как целая бесконечность

Я создал объект, который действует как бесконечность для длинных int. В частности:

#ifndef MU_INF_H
#define MU_INF_H
#include "mu.h"
namespace mu {
  class Inf {
  public:
    bool operator> ( long int i ) { return true; }
    bool operator> ( Inf i ) { return false; }
    ... lots of other boolean operators ...
    Inf& operator+ ( long int i ) { return *this; }
    Inf& operator+ ( Inf i ) { return *this; }
    ... lots of other integer operators ...
  };   // class Inf
}      // namespace mu
#endif

И все это работает очень хорошо, позволяя мне запускать модульные тесты формы:

  mu::Inf inf;
  long int n = -1;
  long int z = 0;
  long int p = 1;

  ASSERT((inf + inf) == inf);
  ASSERT((inf + n) == inf);
  ASSERT((inf + z) == inf);
  ASSERT((inf + p) == inf);

  ASSERT((inf > inf) == false);
  ASSERT((inf > n) == true);
  ASSERT((inf > z) == true);
  ASSERT((inf > p) == true);

Если вы не можете назначить галочку, у меня есть три вопроса:

  • Есть ли в С++ уже что-то подобное и/или есть более очевидный способ, чем то, что я здесь делаю?
  • Я хочу сделать экземпляр Inf доступным в моей системе. Я не могу объявить его static const, потому что это не "простой" объект. Какой правильный подход: глобальный? одноэлементный шаблон?
  • Есть ли способ обрабатывать симметричные операторы, где первый int приходит первым, т.е. ASSERT((1 + inf) == inf)? (Я не буду слишком грустен, если нет.)
4b9b3361

Ответ 1

static const Inf kInfinity; работает и будет использовать конструктор по умолчанию.

operator+ должна быть свободной функцией, которая возвращает значение:

Inf operator+(Inf a, Inf b) { return a += b; }

Вы указали, что предпочитаете возвращать ссылку на kInfinity вместо значения. Это возможно (хотя для меня это кажется немного громоздким); a const ссылка должна быть возвращена, конечно, поскольку kInfinity - const.

Ответ 2

  • Не то, что я знаю, хотя мне кажется, что вы используете ссылки на Inf и фактические объекты в беспорядочной манере в своих перегрузках.

    Обычно вы принимаете аргументы по значению или const reference и возвращаете по значению для всех операторов, кроме составных присвоений (где вы возвращаетесь по ссылке), чтобы получить ожидаемую семантику. Конечно, поскольку ваш объект Inf не имеет состояния, все это имеет смысл только в определенной степени.

  • Я бы использовал глобальный const, чтобы избежать круглых скобок и вызова потенциальной функции в одноэлементном режиме. Точно также это означает, что static не имеет никакого значения (вы не получаете доступ к this каким-либо образом).

  • Вы должны написать свой оператор как свободную функцию:

    inline Inf operator+(long int i, const Inf&) { return *this;} 
    

Ответ 3

Все были очень полезны в руководстве меня к Истинной Пути. Чтобы помочь другим, которые пришли искать ответы, вместо того, чтобы заставить вас сшить ответ вместе со всей нитью, я думал, что опубликую то, что у меня получилось. Разумеется, комментарии, предлагающие уточнения, приветствуются.

#ifndef MU_INDEFINITE_H
#define MU_INDEFINITE_H

namespace mu {

  class Indefinite {
  public:

    static const Indefinite kIndefinite;

    Indefinite() {}
    ~Indefinite() {}

  };

  inline Indefinite operator+ (long int i, Indefinite t) { return Indefinite::kIndefinite; }
  inline Indefinite operator+ (Indefinite t, long int i) { return Indefinite::kIndefinite; }
  inline Indefinite operator+ (Indefinite t1, Indefinite t2) { return Indefinite::kIndefinite; }

  inline Indefinite operator- (long int i, Indefinite t) { return Indefinite::kIndefinite; }
  inline Indefinite operator- (Indefinite t, long int i ) { return Indefinite::kIndefinite; }
  inline Indefinite operator- (Indefinite t1, Indefinite t2) { return Indefinite::kIndefinite; }

  inline Indefinite operator* (long int i, Indefinite t) { return Indefinite::kIndefinite; }
  inline Indefinite operator* (Indefinite t, long int i ) { return Indefinite::kIndefinite; }
  inline Indefinite operator* (Indefinite t1, Indefinite t2) { return Indefinite::kIndefinite; }

  // It not clear what i / Indefinite should produce.  Forbid it for now.
  // inline long int operator/ (long int i, Indefinite t) { return 0; }
  inline Indefinite operator/ (Indefinite t, long int i ) { return Indefinite::kIndefinite; }
  inline Indefinite operator/ (Indefinite t1, Indefinite t2) { return Indefinite::kIndefinite; }

  inline bool operator> (long int i, Indefinite t) { return false; }
  inline bool operator> (Indefinite t, long int i) { return true; }
  inline bool operator> (Indefinite t1, Indefinite t2) { return false; }

  inline bool operator>= (long int i, Indefinite t) { return false; }
  inline bool operator>= (Indefinite t, long int i) { return true; }
  inline bool operator>= (Indefinite t1, Indefinite t2) { return true; }

  inline bool operator< (long int i, Indefinite t) { return true; }
  inline bool operator< (Indefinite t, long int i) { return false; }
  inline bool operator< (Indefinite t1, Indefinite t2) { return false; }

  inline bool operator<= (long int i, Indefinite t) { return true; }
  inline bool operator<= (Indefinite t, long int i) { return false; }
  inline bool operator<= (Indefinite t1, Indefinite t2) { return true; }

  inline bool operator== (long int i, Indefinite t) { return false; }
  inline bool operator== (Indefinite t, long int i) { return false; }
  inline bool operator== (Indefinite t1, Indefinite t2) { return true; }

  inline bool operator!= (long int i, Indefinite t) { return true; }
  inline bool operator!= (Indefinite t, long int i) { return true; }
  inline bool operator!= (Indefinite t1, Indefinite t2) { return false; }

}

#endif