Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ arithmetic operator overloading—automatic widening?

I have a Vector class which represents a 2D vector. It is templated to allow any numerical type to be used for the x and y components. As an example, one of the arithmetic operators I overload is * for multiplying a vector with a scalar:

template <typename T, typename U>
inline const Vector<T> operator*(const Vector<T>& vector, U scalar) {
    return Vector<T>(vector.x * scalar, vector.y * scalar);
}

(I also have a function with the parameters in the opposite order to allow scalar * Vector in addition to Vector * scalar).

As you can see, I use <T, U> instead of simply <T> so that the scalar doesn't have to be the same type as the Vector. When I didn't do this, surprisingly Vector<double> * int wouldn't compile (I thought the int would automatically widen).

In any case, I don't simply want to return a Vector<T>. I want to mimic the built-in types and return whichever has higher precision, T or U. So for example, Vector<int> * double => Vector<double> while Vector<double> * short => Vector<double>.

Is this possible?

like image 337
mk12 Avatar asked Dec 28 '22 05:12

mk12


1 Answers

You can use common_type or decltype to cook up something that gives you the resulting type; and then you have to create the actual vector:

template <typename A, typename B>
std::vector<typename std::common_type<A, B>::type>
operator*(std::vector<A> const & v, B const & x)
{
    std::vector<typename std::common_type<A, B>::type> res;
    res.reserve(v.size());
    for (A a : v) res.push_back(a * x);
    return res;
}

Using decltype, you can get at the result type via:

decltype(std::declval<A>() * std::declval<B>())

For both std::common_type and std::declval you need to #include <type_traits>.

With delayed return types (auto and ->) you can use decltype directly on the function arguments, but using std::declval feels a bit more hygienic, since it doesn't require you to furnish an actual instance of your type (and thus it is applicable even in situations where this isn't possible).

like image 103
Kerrek SB Avatar answered Dec 29 '22 18:12

Kerrek SB