Boost logo

Boost :

From: Andy Little (andy_at_[hidden])
Date: 2006-04-24 13:54:16


"Alberto Ganesh Barbati" wrote
> Andy Little ha scritto:

>> //Signature as thus to prevent too many conversions
>> template <typename T1, typename T2>
>> bool operator()(T1 const & x, T2 const & y) const { return abs(x - y) <
>> eps; }
>> };
>>
>> // ............. possible useage :
>>
>> compare_absolute_error<int> comp(1);
>>
>> int pixel_x =100;
>> float current_pos_x = 100.5;
>>
>> bool grabbed = comp(current_pos_x, pixel_x);
>>
>
> The idea is nice, but in this particular case I think the "fixed"
> version is more suitable. First: the user can be sure about what
> approximation is going to be used for the comparison (in the realm of
> floating point, it's a big help). Second: knowing the type in advance
> allows you to deal correctly with corner cases (infinities, denorm,
> etc.). With the member-template approach that you suggest you would have
> to handle more cases and it might easily get tedious.

There is still only one case. The type is the result_type of T1() - T2 - T()
which is evaluated at compile-time. This is easy to find using Boost.Typeof as
shown below.
The result using the two template parameters is superior because you actually
have much more control over conversions. Because the types arent clamped you
know that T1 and T2 are the exact argument types, rather than the result of a
conversion to T. No narrowing conversions take place though they can with the
original.
The result value of the two functions is different too as shown below, but I
think that the result of the second is the less surprising:
You might argue that only floats should be allowed for T but I would have to ask
then what is wrong with using an int as shown?

#include <cmath>
#include <limits>
#include <boost/typeof/typeof.hpp> // Hopefully in next boost distro
#include <iostream>

template <typename T>
struct compare_absolute_error1{
  T eps;
    compare_absolute_error1(T eps_) : eps(eps_) {}
    bool operator() (T x, T y) const { return abs(x - y) < eps; }
  };

template <typename T>
struct compare_absolute_error2{
  T eps;
  compare_absolute_error2(T eps_) : eps(eps_) {}

//result_type of the comparison
  template <typename T1, typename T2>
    struct result{
        typedef BOOST_TYPEOF_TPL( T1() - T2() - T()) type;
    };
// Signature as thus to prevent too many conversions
 template <typename T1, typename T2>
  bool operator()(T1 const & x, T2 const & y) const {

    // Demo that the result type is available
     typedef typename result<T1,T2>::type result_type;
// whatever...
     result_type infinity = std::numeric_limits<result_type>::infinity();

     return abs(x - y) < eps; }
  };

int main()
{
 int pixel_x = 100;
 float current_pos_x = 99.4F;

//-------------
// note: This version gives
// warning 'argument' : conversion from 'float' to 'int', possible loss of data
 compare_absolute_error1<int> comp1(1);
 bool grabbed1 = comp1(current_pos_x, pixel_x);

//----------------
// this version has no warnings

 compare_absolute_error2<int> comp2(1);

 bool grabbed2 = comp2(current_pos_x, pixel_x);

    std::cout << "compare_absolute_error1 gives " << grabbed1 <<'\n';
    std::cout << "compare_absolute_error2 gives " << grabbed2 <<'\n';

}

regards
Andy Little


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk