Reputation: 936
How can I make it so that (with objects of different template types) A*B and B*A give the same result, where the type of the result is determined according to the usual C++ type promotion rules?
For example:
int main()
{
number<float> A(2.0f);
number<double> B(3.0);
A*B; // I want 6.0 (double)
B*A; // I want 6.0 (double)
return 0;
}
At the moment, I can only multiply objects of the same template type. For example, something like this:
template<typename T>
class number
{
public:
number(T v) : _value(v) {}
T get_value() const { return _value; }
number& operator*=(const number& rhs)
{
_value *= rhs.get_value();
return *this;
}
private:
T _value;
};
template<typename T>
inline number<T> operator*(number<T> lhs, const number<T>& rhs)
{
lhs *= rhs;
return lhs;
}
EDIT: Or, as in the answers, I can multiply objects of different template types, but always returning the same type as lhs. Is there any way to instead return an object whose type is determined by the standard type promotion rules?
EDIT 2: I would like to avoid C++11 features if possible.
Upvotes: 1
Views: 1959
Reputation: 45444
You can use std::common_type<>
to obtain the type required for the return. For example
template<typename X>
struct number
{
// ...
template<typename Y>
number(number<Y> const&other); // needed in line 1 below
template<typename Y>
number&operator=(number<Y> const&other); // you may also want this
template<typename Y>
number&operator*=(number<Y> const&other); // needed in line 2 below
template<typename Y>
number<typename std::common_type<X,Y>::type> operator*(number<Y> const&y) const
{
number<typename std::common_type<X,Y>::type> result=x; // 1
return result*=y; // 2
}
};
I left out the implementations of the templated constructor and operator*=
.
Unfortunately, std::common_type
is C++11, which you want to avoid for obscure reasons. If you only work with built-in types (double
, float
, int
, etc), you can easily implement your own version of common_type
. However, if you want to do sophisticated meta-template programming, it is strongly recommended to move on to C++11 – it's already 4 years old and mostly backwards compatible.
Upvotes: 1
Reputation: 21166
You have to templatize e.g. the rhs
parameters:
template<typename T>
class number
{
public:
number(T v) : _value(v) {}
T get_value() const { return _value; }
template<class E>
number& operator*=(const number<E>& rhs)
{
_value *= rhs.get_value();
return *this;
}
private:
T _value;
};
template<class T, class E, class RET = decltype(T()*E())>
number<RET> operator*(number<T>& lhs, const number<E>& rhs)
{
return lhs.get_value()*rhs.get_value();
}
Upvotes: 2
Reputation: 1
You need a templated overload for the operator*()
template<typename T>
class number {
public:
// ...
template<typename U>
number& operator*=(const number<U>& rhs) {
// ...
}
// ...
};
And the same for the binary operator
template<typename T,typename U>
inline number<T> operator*(number<T> lhs, const number<U>& rhs) {
lhs *= rhs;
return lhs;
}
Upvotes: 1