I have a template class with an overloaded + operator. This is working fine when I am adding two ints or two doubles. How do I get it to add and int and a double and return th
Here be dragons. You're getting into parts of c++ that will probably result in a lot of questions posted to StackOverflow :) Think long and hard about if you really want to do this.
Start with the easy part, you want to allow operator+
to add types that are not always the same as T
. Start with this:
template <typename T2>
TemplateTest<T> operator+(const TemplateTest<T2>& rhs) {
return TemplateTest<T>(this->x + rhs.x);
}
Note that this is templated on T2
as well as T
. When adding doubleTt1 + intTt2
, T
will be doubleTt1
and T2
will be intTt2
.
But here's the big problem with this whole approach.
Now, when you add a double
and an int
, what do you expect? 4 + 2.3 = 6.3
? or 4 + 2.3 = 6
? Who would expect 6
? Your users should, because you're casting the double back to an int
, thus losing the fractional part. Sometimes. Depending on which operand is first. If the user wrote 2.3 + 4
, they would get (as expected?) 6.3
. Confusing libraries make for sad users. How best to deal with that? I dunno...
Newer answer to an old question.
For C++0x you can go with decltype
as other answers have talked about.
I would argue that common_type
is more made for the situation than decltype
.
Here is an example of common_type
used in a generic add:
#include <iostream>
#include <array>
#include <type_traits>
using namespace std;
template <typename T, typename U, unsigned long N>
array<typename common_type<T, U>::type, N> // <- Gets the arithmetic promotion
add_arrays(array<T, N> u, array<U, N> v)
{
array<typename common_type<T, U>::type, N> result; // <- Used again here
for (unsigned long i = 0; i != N; ++i)
{
result[i] = u[i] + v[i];
}
return result;
}
int main()
{
auto result = add_arrays( array<int, 4> {1, 2, 3, 4},
array<double, 4> {1.0, 4.23, 8.99, 55.31} );
for (size_t i = 0; i != 4; ++i)
{
cout << result[i] << endl;
}
return 0;
}
it basically returns the value that different arithmetic operations would promote to. One nice thing about it is that it can take any number of template args. Note: don't forget to add the ::type
at the end of it. That is what gets the actual type result that you want.
For those working pre-c++11 still, there is a boost version of common_type
as well
If this is mainly for basic types, you could help yourself with a metafunction until the new standard rolls in. Something along the lines of
template<typename T1,
typename T2,
bool T1_is_int = std::numeric_limits<T1>::is_integer,
bool T2_is_int = std::numeric_limits<T2>::is_integer,
bool T1_is_wider_than_T2 = (sizeof(T1) > sizeof(T2)) > struct map_type;
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, true > { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, b, b, false> { typedef T2 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, false, true , b> { typedef T1 type; };
template<typename T1, typename T2, bool b> struct map_type<T1, T2, true , false, b> { typedef T2 type; };
template<typename T, typename U>
typename map_type<TemplateTestT<T>, TemplateTest<U> >::type
operator+(TemplateTest<T> const &t, TemplateTest<U> const &u) {
return typename map_type<TemplateTest<T>, TemplateTest<U> >::type(x + t1.x);
}
Of course, this is best combined with the char_traits idea:
template <typename A, typename B>
struct add_traits
{
typedef A first_summand_t;
typedef B second_summand_t;
typedef typename map_type<A, B>::type sum_t;
};
So that you can still specialise for types that don't have a numeric_limits overload.
Oh, and in production code, you'll probably want to properly namespace that and add something for signed/unsigned mismatches in integer types.