Добавление оператора перегрузки == с enable_if - PullRequest
0 голосов
/ 27 апреля 2018

У меня есть рабочая точка класса шаблона с перегрузкой для operator==.

Из-за сравнения с плавающей запятой я пытался добавить вторую перегрузку с enable_if для плавающей запятой, чтобы использовать почти равную функцию.

Это моя попытка:

template<typename T>
class Point2D
{
public:
   Point2D(T x, T y);

   Point2D& operator= (const Point2D& point);
   bool     operator==(const Point2D& point) const;
   bool     operator!=(const Point2D& point) const;
};

template<typename T>
Point2D<T>::Point2D(T x, T y) : x_(x), y_(y)
{
}

template<typename T>
Point2D<T>& Point2D<T>::operator=(const Point2D& point)
{
   if(this != &point)
   {
      x_ = point.x_;
      y_ = point.y_;
   }

   return *this;
}

template<typename T>
bool Point2D<T>::operator==(const Point2D& point) const
{
   return (x_ == point.x_) && (y_ == point.y_);
}

template<typename T>
typename std::enable_if<std::is_floating_point<T>::value, bool>::type
Point2D<T>::operator==(const Point2D& point) const
{
   return Traits::almost_equal(x_, point.x_) &&
          Traits::almost_equal(y_, point.y_);
}

Примечание:

  • Это упрощенный пример.

  • Код фактически работает без перегрузки enable_if

  • Я должен разделить декларацию и реализацию (как в .h), поэтому, пожалуйста, обратитесь к коду как есть.

Ошибка, которую выдаёт мне компилятор:

error: prototype for typename std::enable_if<std::is_floating_point<_Tp>::value, bool>::type Point2D<T>::operator==(const Point2D<T>&) const
  does not match any in class Point2D<T>
  Point2D<T>::operator==(const Point2D& point) const
  ^

error: candidate is: bool Point2D<T>::operator==(const Point2D<T>&)
const bool Point2D<T>::operator==(const Point2D& point) const
      ^

Я не понимаю, на что ссылается ошибка.

Ответы [ 2 ]

0 голосов
/ 27 апреля 2018

Действительно, просто не делай этого. Сделайте это вместо:

template<typename T>
class Point2D
{
  bool equals(const Point2D& other, std::true_type is_floating_point ) const;
  bool equals(const Point2D& other, std::false_type is_floating_point ) const;
public:
  Point2D(T x, T y);

  Point2D& operator= (const Point2D& point);
  bool     operator==(const Point2D& point) const;
  bool     operator!=(const Point2D& point) const;
};

сейчас:

template<typename T>
bool Point2D<T>::operator==(const Point2D& point) const
{
  return this->equals(point, std::is_floating_point<T>{});
}
template<class T>
bool Point2D<T>::equals(const Point2D& point, std::false_type /*is_floating_point*/ ) const {
  return (x_ == point.x_) && (y_ == point.y_);
}
template<class T>
bool Point2D<T>::equals(const Point2D& point, std::true_type /*is_floating_point*/ ) const {
  return Traits::almost_equal(x_, point.x_) &&
      Traits::almost_equal(y_, point.y_);
}

это отправка тегов. Он чище и проще и требует меньше времени для компиляции, чем SFINAE enable-if.

0 голосов
/ 27 апреля 2018

Ошибка ясна - ваше определение не соответствует вашему объявлению. Вам нужен точно такой же enable_if как в вашем прототипе, так и в определении. Кроме того, ваш enable_if не будет работать, поскольку это должно произойти во время замены (SFINAE).

Чтобы сделать вещи более читабельными, вы можете определить псевдоним и использовать конечные типы возврата :

template<typename T>
class Point2D
{
   template <typename U>
   using EnableIfFloat = 
      typename std::enable_if<std::is_floating_point<U>::value, bool>::type;

public:
   Point2D(T x, T y);

   template <typename U = T>
   auto operator==(const Point2D& point) const -> EnableIfFloat<U>&;
   bool operator==(const Point2D& point) const;
   bool operator!=(const Point2D& point) const;
};

Определение:

template<typename T>
template<typename U>
auto Point2D<T>::operator==(const Point2D& point) const -> EnableIfFloat<U>&
{
   return Traits::almost_equal(x_, point.x_) &&
          Traits::almost_equal(y_, point.y_);
}
...