Reputation: 2354
I have a working template class point with an overload for operator==
.
Because of floating point comparison, I was trying to add a second overload with enable_if
for floating point to use an almost equal function.
This is my attempt:
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_);
}
Note:
This is a semplified example.
The code actually work without the enable_if overload
I have to separate declaration and implementation (both in .h), so please refer to the code as is.
The error the compiler gives me is
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 ^
I don't understand what the error is referring to.
Upvotes: 3
Views: 1636
Reputation: 275500
Really, just don't do that. Do this instead:
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;
};
now:
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_);
}
this is tag dispatching. It is cleaner and easier and takes less time to compile than SFINAE enable-if stuff.
Upvotes: 2
Reputation: 93294
The error is clear - your definition does not match your declaration. You need the exact same enable_if
both in your prototype and definition. Also, your enable_if
will not work, as it needs to happen during substitution (SFINAE).
To make things more readable, you can define an alias and use trailing return types:
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;
};
Definition:
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_);
}
Upvotes: 2