Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Comparing == != in templates

What is the correct way to perform == and != operators in template classes? Assume this code:

template<typename T>
class C {
        T x, y;

        public:
        C(T a, T b) : x(a), y(b) {}

        bool cmp() {
                return x == y;
        }

};

int main()
{
        // OK
        C<int> i(1,2);
        i.cmp();

        // not OK
        C<double> d(1.0, 2.0);
        d.cmp();

        return 0;
}

If you build it with g++ -Wfloat-equal, you'll get

warning: comparing floating point with == or != is unsafe [-Wfloat-equal]

because you can't simply compare float variables.


Update

I've solved the problem using type_traits and enable_if like this (thanks @Andrew and @OMGtechy):

#include <type_traits>
#include <limits>
#include <cmath>
#include <iostream>

using namespace std;

template <typename IntegralType>
typename std::enable_if<std::is_integral<IntegralType>::value, bool>::type
equal(const IntegralType& a, const IntegralType& b) {
        return a == b;
}

template <typename FloatingType>
typename std::enable_if<std::is_floating_point<FloatingType>::value, bool>::type
equal(const FloatingType& a, const FloatingType& b) {
        return std::fabs(a-b) < std::numeric_limits<FloatingType>::epsilon();
}

template<typename T>
class C {
    T x, y;

    public:
    C(T a, T b) : x(a), y(b) {}

    bool cmp() {
        return equal(x, y);
    }

};

int main()
{
    // OK
    C<int> i(1,2);
    cout << i.cmp() << endl;

    // not OK
    C<double> d(1.0, 1.0);
    cout << d.cmp() << endl;

    return 0;
}
like image 433
Michal Špondr Avatar asked Dec 01 '14 12:12

Michal Špondr


People also ask

What is a comparison template in Excel?

With this accessible comparison Excel template, you can compare different items. This simple comparison list template allows you to easily list important features, rank the features, and add notes as you compare. Use this comparison chart template to compare products, menu items, or anything else you need to compare.

What is a price comparison chart template?

A price comparison chart or vendor comparison template allows you to make comparisons between prices for you to make a more informed decision. You can also use this template to perform your own evaluation of various products offered at different prices and price ranges.

Why do you need a vendor comparison template?

You may also need a vendor comparison template to conduct a competitive analysis if you want to have a better understanding of the market trends. Use it to see how the pricing structures and products of a company compare to other companies in the same industry. Adding other details or points of comparison on the template makes it more versatile.

How to make comparison of two or more things/objects better?

Charts, graphs make it easier to understand. Below are collection of comparison charts templates which helps to make comparison of two or more things/objects in a better way. You can check these templates and download too. How useful was this post? Click on a star to rate it!


1 Answers

This question seems to be asking two things:

  1. How can I do floating point comparisons without using operator==, and
  2. how can I modify the behaviour of a template depending on the type passed to it.

One answer to the second question is to use type traits. The code below demonstrates this for your situation, providing a comparison_traits for general types (using ==) and a specialisation for doubles, using a tolerance (which answers the first question, too).

#include <cmath>

template <typename T> struct comparison_traits {
  bool equal(const T& a, const T& b) {
    return a == b;
  }

  // etc.
};

template<> struct comparison_traits<double> {
  bool equal(const double& a, const double& b) {
    return fabs(a - b) < 1e-15; // or whatever...
  }
};

template <typename T>
class C {
  T x, y;

  public:
    C(const T& a, const T& b) : x(a), y(b) {}

    bool cmp() {
      return comparison_traits<T>::equal(x, y);
    }
};

int main() {
  // OK
  C<int> i(1, 2);
  i.cmp();

  // Now OK too...
  C<double> d(1.0, 2.0);
  d.cmp();

  return 0;
}

Other options include:

  • Providing a template parameter that allows you to specify a comparison function, defaulting to std::equal_to

  • Specialising your template for double, so that you can write a different implementation of cmp()

like image 118
Andrew Avatar answered Oct 03 '22 16:10

Andrew