Reputation: 23
I am trying to implement a Vector3 struct in C++. I am overloading the "*" operator for handling multiplication with the scalar values. So it will work like this:
v1 = Vector3(1.0f, 1.0f, 1.0f);
v2 = 2*v1;
v3 = 2.4f*v1;
v4 = 2.4*v1;
All 3 operations will return a Vector3 instance. However, I don't want to implement 3 functions for this purpose.
Vector3 operator * (int& const val) {
float _val = static_cast<float> (val);
return Vector3(x * _val, y * _val, z * _val);
}
Vector3 operator * (double& const val) {
float _val = static_cast<float> (val);
return Vector3(x * _val, y * _val, z * _val);
}
Vector3 operator * (float& const val) {
return Vector3(x * val, y * val, z * val);
}
Is there a better way of doing this with one function?
Upvotes: 2
Views: 785
Reputation: 7100
Since you are casting all of the types to float
again, you don't need that.
If you defined your function to accept a float
, then passed an int
or any convertible type, it would be cast to float
automatically. The following code shows that
#include <typeinfo>
#include <iostream>
struct Vector3
{
Vector3(float x, float y, float z): x{x}, y{y}, z{z}{}
float x, y, z;
Vector3 operator*(float val)const{
return Vector3{val * x,val * y,val * z};
}
};
int main(){
Vector3 v1{1,2,3};
auto v2 = v1*2;
std::cout << typeid(v2.x).name();
}
If you want to use the multiplication in reverse order
#include <typeinfo>
#include <iostream>
struct Vector3
{
Vector3(float x, float y, float z): x{x}, y{y}, z{z}{}
float x, y, z;
};
Vector3 operator*(float val, const Vector3& v){
return Vector3{val * v.x,val * v.y,val * v.z};
}
int main(){
Vector3 v1{1,2,3};
auto v2 = 2*v1;
std::cout << typeid(v2.x).name();
}
I used public members for simplicity. u may want to use private ones with setters and getters.
Upvotes: 2
Reputation: 51874
If you really must use reference parameters and the float
data type internally, and you wish to avoid compiler warnings about implicit conversions, then you can use a templated operator function (note also the modified position of the const
qualifier):
template<typename T>
Vector3 operator * (const T& val)
{
float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
return Vector3(x * mul, y * mul, z * mul);
}
You will also need to use a Vector3
object as the first operand of the *
operator:
int main()
{
Vector3 v1 = Vector3(1.0f, 1.0f, 1.0f);
// Vector3 v2 = 2 * v1;
// Vector3 v3 = 2.4f * v1; // These won't work!
// Vector3 v4 = 2.4 * v1;
Vector3 v2 = v1 * 2;
Vector3 v3 = v1 * 2.4f; // But these will
Vector3 v4 = v1 * 2.4;
return 0;
}
EDIT: If you want a 'commutative' operator (that is, one in which you could use the scalar operand in either position), then you can declare a friend
operator that takes two arguments (the constant and a class reference):
template<typename T>
friend Vector3 operator * (const T& val, const Vector3& vec)
{
float mul = static_cast<float>(val); // Change this to any specific conversion/cast you want
return Vector3(vec.x * mul, vec.y * mul, vec.z * mul);
}
Upvotes: 1
Reputation: 1293
As I see, it's enough to define/declare variant with double
and it will work with floats and integers as well.
Here is compilable example (just test & demonstration):
class Vector3 {
public:
Vector3(double x, double y, double z): x(x), y(y), z(z) { }
Vector3 operator * (double val) {
return Vector3(x * val,
y * val,
z * val);
}
private:
double x { 0 };
double y { 0 };
double z { 0 };
};
int main()
{
int a = 1;
float b = 2.1;
double c = 3.5;
Vector3 vec1(1, 2.1f, 3);
Vector3 vec2(a, b, c);
auto vec3 = vec1 * a;
auto vec4 = vec1 * b;
auto vec5 = vec1 * c;
return 0;
}
Upvotes: 0