Caduchon
Caduchon

Reputation: 5231

How can I define floating point constants depending on template type?

In my code, I have a lot of template algorithms where the template type must be a floating point (float, double, or long double). Some of these algorithms require a default epsilon value. Example:

template <typename FloatType>
bool approx(FloatType x1, FloatType x2)
{
  const FloatType epsilon; // How can I set it ?
  return abs(x2 - x1) < epsilon;
}

How can I define it ? I tried the following, it's accepted by gcc, but it's not standard (and not valid in C++11). I know it's possible in C++11, but I have to be compatible with c++03.

template <typename FloatType>
struct default_epsilon
{};

template <>
struct default_epsilon<float>
{
  static const float value = 1.0e-05f;
};

template <>
struct default_epsilon<double>
{
  static const double value = 1.0e-10;
};

template <>
struct default_epsilon<long double>
{
  static const long double value = 1.0e-12l;
};

// Then, I use it like that :
template <typename FloatType>
bool approx(FloatType x1, FloatType x2)
{
  return abs(x2 - x1) < default_epsilon<FloatType>::value;
}
// or that
bool approx(FloatType x1, FloatType x2, FloatType epsilon = default_epsilon<FloatType>::value)
{
  return abs(x2 - x1) < epsilon;
}

Upvotes: 1

Views: 377

Answers (2)

Fareanor
Fareanor

Reputation: 6805

If you don't want to use std::numeric_limits<FloatType>::epsilon(), I think you can do as proposed in comments: Initialize the static members outside class definition.

You can write:

#include <cmath>

template <typename FloatType>
struct default_epsilon
{};

template <>
struct default_epsilon<float>
{
    static const float value;
};
template <>
struct default_epsilon<double>
{
    static const double value;
};
template <>
struct default_epsilon<long double>
{
    static const long double value;
};

template <typename FloatType>
bool approx(FloatType x1, FloatType x2)
{
    return std::abs(x2 - x1) < default_epsilon<FloatType>::value;
}

And somewhere in your .cpp file:

const float default_epsilon<float>::value = 1.0e-05f;
const double default_epsilon<double>::value = 1.0e-10;
const long double default_epsilon<long double>::value = 1.0e-12l;

And it should do the trick.

Upvotes: 2

Ahmed Anter
Ahmed Anter

Reputation: 650

use traditional c++ casting operator overload

class MyEpsilon
{
public:
    operator float() {return 1.0e-05f;};
    operator double() { return 1.0e-10; };
    operator long double() { return 1.0e-12l; };
};

template<class T>
class MyTest {
public:
    T DoSome() {
        MyEpsilon e;
        return T(e);
    }
};

Upvotes: 0

Related Questions