Overloading operators for use on my new class

I have defined my own class usign template for dealing with vectors.

It goes like this:

1
2
3
4
5
6
7
template <typename any_type> class v3{
    public:
        any_type x;
        any_type y;
        any_type z;
    //some more code here, functions, overloaded operators,..
    };


I have overloaded operators for vector addition, subtraction, all operations between vectors. Now my next step is to be able to multiply my vector with a scalar number, or devide it by it. Now this number can be of different types, int, long, double, float,.. and it can be on left or right side of vector (ok in dividing only on right). Now how would i overload the * and / in as little code as possible with best performance? Can i overload it for int, long,... at once? i dont want to describe all the combinations. is there also a chance to overload it only for those i want, i mean, if somebody would try to multiply vector with string or char, it should be an error, so i need to overload it only for those that i want, and for none others. How can i go about doing this?



Just to give an idea what i have in that green comment:
1
2
3
    v3<any_type> operator ^ (const v3<any_type>& a){
        return v3<any_type>(y*a.z-z*a.y,z*a.x-x*a.z,x*a.y-y*a.x);
        }

This is just the definition of cross product. Another question, should i use this-> ? I am actually suprised it works without it. Is there a difference using it or not?


Thank you for all your help in advance!
Last edited on
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <iostream>
#include <type_traits>

template < typename T >
class v3 {

        T x {};
        T y {};
        T z {};

    public:
        v3() = default ;
        v3( const T& a, const T& b, const T& c ) : x(a), y(b), z(c) {}

        // ...

        // http://en.cppreference.com/w/cpp/types/is_arithmetic
        // http://en.cppreference.com/w/cpp/types/conditional
        // http://en.cppreference.com/w/cpp/types/integral_constant
        template < typename A, typename B > // true if both A and B are arithmetic types
        struct are_arithmetic : std::conditional< std::is_arithmetic<A>::value &&
                                                  std::is_arithmetic<B>::value,
                                                  std::true_type, std::false_type >::type {};

        // v3<T> *= arithmetic_type
        // http://en.cppreference.com/w/cpp/types/enable_if
        template < typename U > // enable only if both T and U are arithmetic types
        typename std::enable_if< are_arithmetic<T,U>::value, v3<T>& >::type
        operator *= ( U value ) { x *= value ; y *= value ; z *= value ; return *this ; }

        // v3<T> * arithmetic_type
        template < typename U > friend // enable only if both T and U are arithmetic types
        typename std::enable_if< are_arithmetic<T,U>::value, v3<T> >::type
        operator * ( v3<T> vec, U value ) { return vec *= value ; }

        // arithmetic_type * v3<T>
        template < typename U > friend // enable only if both T and U are arithmetic types
        typename std::enable_if< are_arithmetic<T,U>::value, v3<T> >::type
        operator * ( U value, v3<T> vec ) { return vec *= value ; }
        
        // likewise for operator /

        friend std::ostream& operator<< ( std::ostream& stm, const v3<T>& vec )
        { return stm << "{ " << vec.x << ", " << vec.y << ", " << vec.z << " }" ; }
};

int main()
{
    v3<double> vec { 12.34, 23.45, 34.56 } ;
    std::cout << vec << '\n' ;

    vec *= 1.2 ;
    std::cout << vec << '\n' ;

    std::cout << vec*2 << '\n' << 3*vec << '\n' ;

    // vec * "hello" ; // *** error: invalid operands, no match for operator *
}

http://coliru.stacked-crooked.com/a/eae46c4de38a49a9
http://rextester.com/GUC18598

> should i use this-> ? I am actually suprised it works without it. Is there a difference using it or not?

In some cases, where the name of a member is hidden, it is useful. For instance:
struct A { int m ; void foo( int m ) { this->m = m ; /* or */ A::m = m ; /* or */ this->A::m = m ; } };

You may want to ignore this for now:
it can also be used in templates to postpone the look up of a name to the second phase of the two-phase look up.

Otherwise, use this->member or type::member if you feel that it makes your code more readable.
If you do use it, use it consistently; use the same form, and use it everywhere.
wooow. I love your work JLBorges! This is incredible helpful! Really thank you! I understand all the code, but where could i read more about using : and :: ? I need to get more familiar with it. What should i search for? When i was reading about namespaces i didnt come across such advance uses.
> where could i read more about using : and :: ?

Member initializer lists in constructors: http://en.cppreference.com/w/cpp/language/initializer_list

Name lookup: http://en.cppreference.com/w/cpp/language/lookup
Unqualified name lookup: http://en.cppreference.com/w/cpp/language/unqualified_lookup
Qualified name lookup: http://en.cppreference.com/w/cpp/language/qualified_lookup

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
#include <iostream>
#include <string>

int value = 99 ; // namespace scope

struct A
{
    A() = default ;

    // http://en.cppreference.com/w/cpp/language/initializer_list
    // there are two member initialisers, value(v) and str(s)
    // the member initialiser list is : value(v), str(s)
    A( int v, std::string s ) : value(v), str(s) {}

    int value = 0 ; // the name 'value' (class scope) hides the name ::value
    std::string str = "hello" ;
};

struct B : A
{
    int value = 7 ; // the name 'value' (B::value) hides the name 'A::value'
    int n = 88 ;

    void foo( int n ) // the name 'n' (block scope) hides the name 'B::n' (class scope)
                      // microsoft: *** warning: declaration of 'n' hides class member
    {
        // Within a scope, unqualified name lookup can be used to
        // associate the name with its declaration.
        // http://en.cppreference.com/w/cpp/language/scope
        // lookup of unqualified name 'n' finds 'n' at block scope
        n = n ; // trivial self assignment
        // clang++: *** warning: explicitly assigning value of variable of type 'int' to itself

        this->n = 555 ; // assign to the non-static member 'n' (class scope)
        B::n = 555 ; // same as above
        this->B::n = 555 ; // same as above

        // lookup of unqualified name 'value' finds B::value at class scope (B)
        value = 10 ;
        this->value = 10 ; // same as above
        B::value = 10 ; // same as above
        this->B::value = 10 ; // same as above

        A::value = 200 ; // assign to (inherited) value at class scope (A)
        this->A::value = 200 ; // same as above

        std::cout << "\nfoo(" << n << ")\n-----------\n"
                  << n << '\n' // argument n
                  << this->n << ' ' << B::n << ' ' << this->B::n << '\n' // 555 555 555
                  << ::value << '\n' // 99
                  << value << ' ' << B::value << ' ' << this->value << '\n' // 10 10 10
                  << A::value << ' ' << this->A::value << '\n' // 200 200
                  << "------------------------------------\n" ;
    }
};

int main()
{
    B b ;
    std::cout << b.n << ' ' << b.B::n << '\n' // 88 88
              << b.value << ' ' << b.B::value << '\n' // 7 7
              << b.str << ' ' << b.B::str << ' ' << b.A::str << '\n' // hello hello hello
              << value << ' ' << ::value << '\n' // 99 99
              << b.value << ' ' << b.B::value << ' ' << b.A::value << '\n' ; // 7 7 0

    b.foo(2000) ;
}

http://coliru.stacked-crooked.com/a/5f0306b50516a315
http://rextester.com/THTEB46157
Thank you! That is incredible, all that i needed. I will also go about reading all the links now.

Marking this topic as solved, all thanks to JLBorges!
Topic archived. No new replies allowed.