SnakeLikeCoding
SnakeLikeCoding

Reputation: 23

C++ function that can take integer or float or double or any other castable to float

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

Answers (3)

asmmo
asmmo

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();
}

Live

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

Adrian Mole
Adrian Mole

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

Ihor Drachuk
Ihor Drachuk

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

Related Questions