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;
}
This question seems to be asking two things:
How can I do floating point comparisons without using operator==, and
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()
It depends how it will be used. Comparing floats properly depends on the context.
I would recommend what #Niall says: add a comparator template parameter, defaulting to std::equal_to. This will allow callers to control how values are compared. See for example the docs on std::sort to see how a comparator parameter is used. The downside to this is that it's the caller's responsibility to account for comparing floats. If they forget, then they'll get the compiler warning you see.
Another option is template class specialization. Make a specialization for your class to deal specifically with float or double types, and compare them differently using whatever logic you prefer. Probably not the best solution though. The benefit to this is that callers no longer need to remember to specify a comparator.
If you ask why you get this warning:
here some example:
double a,b;
a=10.0/13.0;
b = a/3;
b*=3;
std::cout<<"a="<<a<<std::endl;
std::cout<<"b="<<b<<std::endl;
if(a!=b){
std::cout<<"NOT equal!!"<<std::endl;
std::cout<<"a-b="<<a-b<<std::endl;
}
else
std::cout<<"equal"<<std::endl;
if you'll do the math a and b are clearly equal.
but this is the output I've got:
a=0.769231
b=0.769231
NOT equal!!
a-b=-1.11022e-016
because it is not so accurate, a proper comparison for double should define some tolerancy:
for example(tolerancy may change according needs):
int compare(double a, double b)
{
double tolerancy = 0.000001;
if (abs(a-b) < tolerancy) return 0;
else if (a>b) return 1;
else /*if (a<b)*/ return -1;
}
and if I use this compare i get:
a=0.769231
b=0.769231
equal
Related
In a project I'm working on I have a templated function similar to this where all of the arguments should be of type T
#include <iostream>
template<typename T> bool aWithinBOfC(T a, T b, T c)
{
return std::abs(a - c) < b;
}
the issue I'm having is it won't compile if all of the arguments are not of the same type but it seems reasonable that it should implicitly cast similar types to the one with the highest resolution before evaluation. Is there any way to get a call like this to be valid?
int main()
{
double a{1.2};
double b{1.4};
float c{0.1f};
std::cout << aWithinBOfC(a, b, c) << std::endl;
}
Something along these lines, perhaps:
template<typename T>
bool aWithinBOfCImpl(T a, T b, T c) {
/* actual implemenattion */
}
template <typename ... Args>
auto aWithinBOfC(Args... args) {
return aWithinBOfCImpl<std::common_type_t<Args...>>(args...);
}
Demo
You don’t need implicit conversions at the call site. The compiler will implicitly convert the types to the largest one in the expression in the return statement.
template <class T, class U, class V>
bool aWithinBOfC(T a, U b, V c) {
return std::abs(a - c) < b;
}
How do you create a generic num like class so that the only thing that matters is that the relevant member function/operator exists?
I've read up on SFINAE but I don't get it to be honest.
#include <iostream>
template<typename T>
class Numeric {
const T a;
public:
Numeric(const T &v) : a(v) {}
T operator+(const Numeric<T> &b) {
return a + b.a;
}
};
int main() {
Numeric<float> fl1(35.5);
Numeric<float> fl2(10.5);
Numeric<uint64_t> i64(10000);
std::cout << (i64 + fl1 + fl2) << std::endl;
return 0;
}
Here, fl1 + fl2 would be fine but since the operator definition says T is the same type i64 can't be mixed with fl1 or fl2.
Are templates the right thing here, would it be better to use the object hierarchy defining a top level Num for e.g. that defines all the operators and have a sub class for each supported type? Though I don't think that solves the mixing types problem.
EDIT 1:
Background in res to Barry/lisyarus:
I'm changing an old code base which has a type defined like this:
template<typename a> struct NumT : public SomeSuperType<a> { mp::cpp_int val;};
The change is to add support for native float and double types in this NumT type in a transparent a way as possible.
Ideally NumT shouldn't change beyond changing the decl. type of val.
Existing code just does a + b and other arithmetic operations on val, not breaking the existing API stuff is important.
i64 + fl1 + fl2 == 10046
There's a reason why numeric types are different (int, float and so on), trying to commonize them can get awry. Nonetheless, you can use std::common_type to deduce the type that can contain both.
Mind you there will be a loss of "precision" here.. For example, if you have an unsigned long long of 1434263462343574573ULL, converting it to double will lose some significant digits.
#include <iostream>
#include <type_traits>
template<typename T>
class Numeric {
const T a;
public:
Numeric(const T &v) : a(v) {}
T get() const { return a; }
};
template<typename T, typename U>
Numeric<typename std::common_type<T, U>::type> //With C++14, do std::common_type_t<T, U>
operator + (const Numeric<T>& a, const Numeric<U>& b) {
return a.get() + b.get(); //Works because of the converting constructor
}
template<typename T>
std::ostream& operator << (std::ostream& os, const Numeric<T>& n){
os << n.get();
return os;
}
int main() {
Numeric<float> fl1(35.5);
Numeric<float> fl2(10.5);
Numeric<uint64_t> i64(10000);
std::cout << (i64 + fl1 + fl2) << std::endl;
return 0;
}
This prints:
10046
I have to create a template whose return-value is a pointer to some lambda function (which is determined by template parameters).
The compiler feedback:
error: no matching function for call to ‘laptr(int)’
What's wrong with the code? How to solve the problem?
#include <iostream>
using namespace std;
template <typename T>
T laptr(int par);
int main(){
laptr(1);
return 0;
}
///////////
template <typename T>
T laptr(int par)
{
if (par == 1)
{
int p1 = [](int a, int b)->int{return a*b; };
return p1;
}
else
{
double p2 = [](double a, double b)->double{return a + b; };
return p2;
}
}
You can use a std::function to store a lambda function:
template <typename T>
std::function<T(T,T)> laptr (int par)
{
if(par == 1)
return [](T a, T b)->T {return a*b;};
else
return [](T a, T b)->T {return a+b;};
}
or even a pointer to function
template <typename T>
auto laptr (int par) -> T(*)(T,T)
{
...
}
You can use it like this
auto func = laptr<double>(1);
auto result = func(8,2); // 8*2=16
Your fundamental problem is that:
template <typename T>
...here, T is/must be determined entirely at compile time, but:
T laptr(int par)
par isn't known until run time, and:
if (par == 1)
{
int p1 = [](int a, int b)->int{return a*b; };
return p1;
}
else
{
double p2 = [](double a, double b)->double{return a + b; };
return p2;
}
Here, T isn't known until you've decided which leg of the if statement to execute, so the type 1) must be known before the code finishes compiling, not to mention anything about executing, but 2) can't be determined until the code executes.
Obviously you can't have both of those happen, so the code can't compile.
There are quite a few alternatives -- a pointer to a function, a std::function, a Command object (as defined in Modern C++ Design), etc. All of them will do the job essentially similarly: rather that attempting to return the precise type of each lambda, they're going to define some common type that can hold the type of either lambda, and return an object of that type instead.
Consider the following function that computes the integral or floating-point modulo depending on the argument type, at compile-time:
template<typename T>
constexpr T modulo(const T x, const T y)
{
return (std::is_floating_point<T>::value) ? (x < T() ? T(-1) : T(1))*((x < T() ? -x : x)-static_cast<long long int>((x/y < T() ? -x/y : x/y))*(y < T() ? -y : y))
: (static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(x)
%static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(y));
}
Can the body of this function be improved ? (I need to have a single function for both integer and floating-point types).
Here's one way to clean this up:
#include <type_traits>
#include <cmath>
template <typename T> // integral? floating point?
bool remainder_impl(T a, T b, std::true_type, std::false_type) constexpr
{
return a % b; // or whatever
}
template <typename T> // integral? floating point?
bool remainder_impl(T a, T b, std::false_type, std::true_type) constexpr
{
return std::fmod(a, b); // or substitute your own expression
}
template <typename T>
bool remainder(T a, T b) constexpr
{
return remainder_impl<T>(a, b,
std::is_integral<T>(), std::is_floating_point<T>());
}
If you try and call this function on a type that's not arithmetic, you'll get a compiler error.
I would rather define it this way (template aliases + template overloading):
#include <type_traits>
using namespace std;
// For floating point types
template<typename T, typename enable_if<is_floating_point<T>::value>::type* p = nullptr>
constexpr T modulo(const T x, const T y)
{
return (x < T() ? T(-1) : T(1)) * (
(x < T() ? -x : x) -
static_cast<long long int>((x/y < T() ? -x/y : x/y)) * (y < T() ? -y : y)
);
}
// For non-floating point types
template<typename T>
using TypeToCast = typename conditional<is_floating_point<T>::value, int, T>::type;
template<typename T, typename enable_if<!is_floating_point<T>::value>::type* p = nullptr>
constexpr T modulo(const T x, const T y)
{
return (static_cast<TypeToCast<T>>(x) % static_cast<TypeToCast<T>>(y));
}
int main()
{
constexpr int x = modulo(7.0, 3.0);
static_assert((x == 1.0), "Error!");
return 0;
}
It is lengthier but cleaner IMO. I am assuming that by "single function" you mean "something that can be invoked uniformly". If you mean "a single function template", then I would just keep the template alias improvement and leave the overload. But then, as mentioned in another answer, it would not be clear why you do need to have one single function template.
You ask,
“Can the body of this function be improved?”
Certainly. Right now it is a spaghetti mess:
template<typename T>
constexpr T modulo(const T x, const T y)
{
return (std::is_floating_point<T>::value) ? (x < T() ? T(-1) : T(1))*((x < T() ? -x : x)-static_cast<long long int>((x/y < T() ? -x/y : x/y))*(y < T() ? -y : y))
: (static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(x)
%static_cast<typename std::conditional<std::is_floating_point<T>::value, int, T>::type>(y));
}
You clarify that …
“(I need to have a single function for both integer and floating-point types)”
Well the template is not a single function. It’s a template. Functions are generated from it.
This means your question builds on a false assumption.
With that assumption removed, one way to simplify the function body, which you should do as a matter of course, is to specialize the template for floating point types versus other numeric types. To do that put the function template implementation in a class (because C++ does not support partial specialization of functions, only of classes).
Then you can employ various formatting tricks, including the "0?0 : blah" trick to make the function more readable, with lines and indentation and stuff! :-)
Addendum: delving into your code I see that you cast haphazardly to long int and int with disregard of the invoker's types. That's ungood. It is probably a good idea to write up a bunch of automated test cases, invoking the function with various argument types and big/small values.
template <class T>
constexpr
T
modulo(T x, T y)
{
typedef typename std::conditional<std::is_floating_point<T>::value,
int,
T
>::type Int;
return std::is_floating_point<T>() ?
x - static_cast<long long>(x / y) * y :
static_cast<Int>(x) % static_cast<Int>(y);
}
I believe there is simpler:
// Special available `%`
template <typename T, typename U>
constexpr auto modulo(T const& x, U const& y) -> decltype(x % y) {
return x % y;
}
Note: based on detection of % so also works for custom types as long as they implement the operator. I also made it mixed type while I was at it.
// Special floating point
inline constexpr float modulo(float x, float y) { return /*something*/; }
inline constexpr double modulo(double x, double y) { return /*something*/; }
inline constexpr long double modulo(long double x, long double y) { return /*something*/; }
Note: it would cleaner to have fmod available unfortunately I do not believe it is constexpr; therefore I chose to have non-template modulos for the floating point types which allows you to perform magic to compute the exact modulo possibly based on the binary representation of the type.
You can do that much simpler if you want:
template<typename A, typename B>
constexpr auto Modulo(const A& a, const B& b) -> decltype(a - (b * int(a/b)))
{
return a - (b * int(a/b));
}
Is it somehow possible to reflect the type of the argument of a function at compile time?
So that
int b = add(3, 6)
Would result in a template instantiation in the form of
int add(int a, int b) { return a + b }
out of some however declared function template
A add(A a, B b) { return a + b }
I don't know if that is possible with templates they do not really seem to be made for heavy meta-programming.
template<typename T>
T add(T a, T b) { return a + b; }
Then you can call this with any built-in type (int, short, double, float, etc), and it will instantiate the function add at compile time, according to the type you use.
Note that if you split this into header/source, you will have trouble:
add.h:
template<typename T>
T add(T a, T b);
add.cpp:
template<typename T>
T add(T a, T b) { return a + b; }
main.cpp:
#include "add.h"
int a = 3;
int b = 5;
int i = add(a, b);
When you try to compile this, it will fail at link time. Here's why.
Compiling add.obj does not instantiate the add template method -- because it's never called in add.cpp. Compiling main.obj instantiates the function declaration -- but not the function body. So at link time, it will fail to find the definition of the add method.
Simplest fix is to just put the entire template function in the header:
add.h:
template<typename T>
T add(T a, T b) { return a + b; }
and then you don't even need the add.cpp file at all.
Doesn't this do what you're asking?
template <typename A, typename B>
A add(A a, B b) { return a + b; }
This is hardly "heavy meta-programming".
This is exactly the sort of thing templates do.
template <typename T>
inline T add(T a, T b) { return a + b; }
Allowing two different types gets a little bit trickier but is also possible.
If you plan on using anything other than simple types you want (in a header file):
template <typename A>
inline A add(const A& a, const A& b) { return a + b; }
Note the 'inline'.
As noted by others, the issue with mixed types is how to determine the return type from the argument types. Suppose we stick to simple types and have:
template
inline A add(A a, B b) { return a + b; }
Then this fails (likely with only a warning):
double d = add(1, 1.5); // Sets d to 2.0
So you have to do some work. For example:
template<class A, class B>
struct Promote
{
};
template<class A>
struct Promote<A,A>
{
typedef A Type;
};
template<>
struct Promote<int, double>
{
typedef double Type;
};
template<>
struct Promote<double, int>
{
typedef double Type;
};
The add function becomes:
template<class A, class B>
inline typename Promote<A,B>::Type add(A a, B b)
{
return a + b;
}
What all this does for you is ensure that the return type is the one you specify for adding a given pair of types. This will work even for complex types.
Templates do all their magic at compile time, but that seems to be quite adequate for what you're asking:
template <class T>
T add(T a, T b) { return a + b; }
It does get a bit more complex when the two might not match, so (for example) you could add an int to a double and get a double result. The current standard doesn't really support that1; with C++0x you can look into auto and decltype for such tasks.
1Though Boost typeof will often do the job.