Harry
Harry

Reputation: 936

How to multiply objects of different template type in C++

How can I make it so that (with objects of different template types) A*B and B*A give the same result, where the type of the result is determined according to the usual C++ type promotion rules?

For example:

int main()
{
    number<float> A(2.0f);    
    number<double> B(3.0);
    A*B; // I want 6.0 (double)
    B*A; // I want 6.0 (double)

    return 0;
}

At the moment, I can only multiply objects of the same template type. For example, something like this:

template<typename T>
class number
{
    public:

        number(T v) : _value(v) {}

        T get_value() const { return _value; }

        number& operator*=(const number& rhs)
        {
            _value *= rhs.get_value(); 
            return *this;
        } 

    private:

        T _value;
};

template<typename T>
inline number<T> operator*(number<T> lhs, const number<T>& rhs)
{
  lhs *= rhs;
  return lhs;
}

EDIT: Or, as in the answers, I can multiply objects of different template types, but always returning the same type as lhs. Is there any way to instead return an object whose type is determined by the standard type promotion rules?

EDIT 2: I would like to avoid C++11 features if possible.

Upvotes: 1

Views: 1959

Answers (3)

Walter
Walter

Reputation: 45444

You can use std::common_type<> to obtain the type required for the return. For example

template<typename X>
struct number
{
  // ...

  template<typename Y>
  number(number<Y> const&other);              // needed in line 1 below

  template<typename Y>
  number&operator=(number<Y> const&other);    // you may also want this

  template<typename Y>
  number&operator*=(number<Y> const&other);   // needed in line 2 below

  template<typename Y>
  number<typename std::common_type<X,Y>::type> operator*(number<Y> const&y) const
  {
    number<typename std::common_type<X,Y>::type> result=x;   // 1
    return result*=y;                                        // 2
  }
};

I left out the implementations of the templated constructor and operator*=.


Unfortunately, std::common_type is C++11, which you want to avoid for obscure reasons. If you only work with built-in types (double, float, int, etc), you can easily implement your own version of common_type. However, if you want to do sophisticated meta-template programming, it is strongly recommended to move on to C++11 – it's already 4 years old and mostly backwards compatible.

Upvotes: 1

MikeMB
MikeMB

Reputation: 21166

You have to templatize e.g. the rhsparameters:

template<typename T>
class number
{
public:

    number(T v) : _value(v) {}

    T get_value() const { return _value; }
    template<class E>
    number& operator*=(const number<E>& rhs)
    {
        _value *= rhs.get_value(); 
        return *this;
    } 

private:

    T _value;
};

template<class T, class E, class RET = decltype(T()*E())>
number<RET> operator*(number<T>& lhs, const number<E>& rhs)
{
    return lhs.get_value()*rhs.get_value();
}

Upvotes: 2

πάντα ῥεῖ
πάντα ῥεῖ

Reputation: 1

You need a templated overload for the operator*()

template<typename T>
class number {
    public:
    // ...
    template<typename U>
    number& operator*=(const number<U>& rhs) {
        // ...
    }
    // ...
 };

And the same for the binary operator

template<typename T,typename U>
inline number<T> operator*(number<T> lhs, const number<U>& rhs) {
  lhs *= rhs;
  return lhs;
}

Upvotes: 1

Related Questions