0

I have a Vector class which is inherited by an EulerAngle class. I want to be able to use the operator function from the Vector class on a EulerAngle object without having to rewrite the operator in the EulerAngle class and changing Vector3 to Angle if possible. How could I do this?

class Vector3 {
public:  
    float x, y, z;

    // ctors...
    __forceinline Vector3() : x{}, y{}, z{} {

    __forceinline Vector3( float x, float y, float z ) : x{ x }, y{ y }, z{ z } {

    }

    // functions...

    // operators...
    __forceinline Vector3 &operator +=( const Vector3 &other ) {
        x += other.x;
        y += other.y;
        z += other.z;

        return *this;
    }

    __forceinline Vector3 &operator +=( float scalar ) {
        x += scalar;
        y += scalar;
        z += scalar;

        return *this;
    }

    __forceinline Vector3 operator +( float scalar ) const {
       return Vector3( x + scalar, y + scalar, z + scalar );
    }

    __forceinline Vector3 operator +( const Vector3 &other ) const {
       return Vector3( x * other.x, y * other.y, z * other.z );
    }

}

class EulerAngle : public Vector3 {
private:

};

// example, MSVC says this is an error and that there is no suitable conversion from EulerAngle to Vector3
EulerAngle ang = { 1.f, 1.f, 1.f };
ang += 5.f

After a few answers I added the following code to make this work. However I still want to know if there is a better way to accomplish this?

class EulerAngle : public Vector3 {
public:
    using Vector3::Vector3;

    __forceinline EulerAngle( const Vector3 &other ) : Vector3( other ) {

    }
};
  • Looks like the issue is with the initialization, and has nothing to do with the `operator+=`. "Inheriting constructors" may help you. – aschepler May 07 '19 at 22:29
  • Potentially useful link: https://stackoverflow.com/questions/347358/inheriting-constructors – user4581301 May 07 '19 at 22:31
  • 2
    Sidenote: `__forceinline` might not be as useful as you think. You have to get up reaaaaaaly early in the morning to out optimize an optimizing compiler. – user4581301 May 07 '19 at 22:32
  • Ok that fixes it for the example above. However, for this operator it is still saying that there is no suitable conversion. Like when i do `EulerAngle ang2 = ang + 5.f` -> `__forceinline Vector3 operator +( float scalar ) const { return Vector3( x + scalar, y + scalar, z + scalar ); }` –  May 07 '19 at 22:40
  • [Current Code via GodBolt](https://godbolt.org/z/HNqwSp) @aschepler I used the C++11 using keyword for inheritance, but it still has the error. –  May 07 '19 at 22:50
  • @user4581301 it's not about optimization, it just looks stupid in the generated assembly to have a function only for setting member vars. –  May 07 '19 at 22:53
  • 1
    `Vector3 operator +( float scalar )` returns a `Vector3 `. `Vector3` can use it's compiler-generated copy constructor to do the construction, but no such luck for `EulerAngle`. I think you'll need a `EulerAngle(const Vector3& in): Vector3(in) {}` – user4581301 May 07 '19 at 23:23
  • @user4581301 Ye that works –  May 07 '19 at 23:26
  • Works, but unsatisfying. You should move the code from the godbolt link to your question and see if anyone can come up with a better solution. Just because I don't think there is one doesn't mean there isn't one. Some darn crafty people lurking around this site. – user4581301 May 07 '19 at 23:30

2 Answers2

2

You could make use of user-defined conversion from Vector3 to the type you want with static assertion when it is not inherited from Vector3.

template<typename T>
operator T() const
{
    static_assert(std::is_base_of<Vector3, T>::value, "T is not inherited from Vector3");
    return T{x,y,z};
}

LIVE DEMO

===============================================================

ADDON

With C++20 and the introduction of concepts, the above code can be rewritten to:

template<typename T>
requires std::DerivedFrom<T,Vector3>
constexpr operator T() const
{
    return T{x,y,z};
}

LIVE DEMO

serkan.tuerker
  • 1,681
  • 10
  • 20
0

Add implicit constructor from Vector3 and using for Vector3 constructor in EulerAngle class

class EulerAngle : public Vector3 {
    using Vector3::Vector3;
    EulerAngle(const Vector3& from) : Vector3(from) {}
}

if you want to do it like this

EulerAngle ang = { 1.f, 1.f, 1.f };
ang += 5.f;
EulerAngle ang2 = ang + 5.f;
EulerAngle ang3 = Vector3{ 2.f, 2.f, 2.f } + ang2;
Oliort UA
  • 1,568
  • 1
  • 14
  • 31