Overloading assignment operator in a class template that can cast to another template type
Asked Answered
B

3

9
#ifndef NUMBER_HPP
#define NUMBER_HPP

template <class T>
class Number
{
public:
  Number( T value ) : m_value( value )
  {
  }

  T value() const
  {
    return m_value;
  }

  void setValue( T value )
  {
    m_value = value;
  }

  Number<T>& operator=( T value )
  {
    m_value = value;
  }

  //  template <class T2>
  //  Number<T2>& operator=( const Number<T>& number )
  //  {
  //    m_value = number.value();

  //    return *this;
  //  }

private:
  T m_value;
};

typedef Number<int> Integer;
typedef Number<float> Float;
typedef Number<double> Double;

#endif // NUMBER_HPP

The commented assignment operator overloading is my attempt to do what I want, I thought it might provide a better description than the one above the snippet.

I want to be able to do the following:

Float a(10);
Integer b(20);

a = b;

Where a then would be casted to an int and given the value of b, but still be an instance of class Number.

Is it possible? Can you help me out here?

Thanks in advance.

Brunhilde answered 29/11, 2011 at 4:43 Comment(2)
What's wrong with the default assignment operator, combined with the implicit conversion provided by the constructor? That will do exactly what your operators are trying to do, without having to write any code.Dallapiccola
It's been a while since I did C++ but you can also override the cast/conversion operator.Carnarvon
R
11

You should do this:

template <class T2>
Number<T>& operator=( const Number<T2>& number )
{
    m_value = number.value();
    return *this;
}

That is, use T2 in the parameter type, not in the return type!

I would rather use different letter for template parameter:

template <class U>
Number<T>& operator=( const Number<U>& number )
{
    m_value = number.m_value; //I would also directly access the member variable!
    return *this;
}

I think, it is better to use explicit cast, if you want to use class type as template argument and whose constructor has been declared explicit:

 m_value = static_cast<T>(number.m_value); 

By the way, the other operator= should be implemented as:

Number<T>& operator=(T const & value ) //accept by const reference
{
    m_value = value;
    return *this; //you've to return!
}
Rigobertorigor answered 29/11, 2011 at 4:51 Comment(1)
Yep, thanks a lot. @SethCarnegie asked what happened when I uncommented the code, at the same time I uncommented it I realized the way I was checking the result was with printf() using %d instead of %f of the float. Silly. Thanks to both of you.Brunhilde
P
5

You have some of the Ts in the wrong place. It should be

template <class T2>
Number<T>& operator=( const Number<T2>& number )
{
    m_value = number.value();
    return *this;
}

This will let you do

Integer a(4);
Float b(6.2f);

a = b;

cout << a.value() << endl;

and it will print 6, a behaviour similar to that of the int and float types you are imitating.

Projector answered 29/11, 2011 at 4:52 Comment(0)
S
0

In case you want more of a built-in feel, the value() and setValue() can be replaced with assignment and cast:

#include <iostream>

template <class T>
class Number
{
public:
    Number() : m_value( 0 ) { }
    Number( T value ) : m_value( value ) { }
    
    Number<T>& operator=( T value )
    {
        m_value = value;
        return *this;
    }

    template <class T2>
    Number<T>& operator=( const Number<T2>& in )
    {
        m_value = static_cast< T >( in );
        return *this;
    }
    
    operator int() const
    {
        return m_value;
    }

    operator float() const
    {
        return m_value;
    }

    friend std::ostream& operator<<( std::ostream& s, Number<T>& in )
    {
        s << static_cast< T >( in );
        return s;
    }

private:
    T m_value;
};

typedef Number<int> Integer;
typedef Number<float> Float;
typedef Number<double> Double;

int main()
{
    Integer a[5] = { 0, 1, 2, 3, 4 };
    Double b(3);
    
    a[0] = 1;
    b = 2;
    b = a[0];
    
    std::cout << "b is " << b << std::endl;
    std::cout << "a[3] is " << a[3] << std::endl;

    return 0;
}
Slaty answered 19/10, 2023 at 21:38 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.