jeudi 23 avril 2015

Implicit conversion of int to double in template operator*<>

I have a template class typically instantiated by <double>.

My header has something like:

template <typename T> class F;
// Non-member functions
template <typename T> const F<T> operator*(F<T> lhs, const F<T>& rhs);
template <typename T> const F<T> operator*(const F<T>& lhs, const T& rhs);

template <typename T>
class F
{
    // blah blah
    F<T>& operator*=(const F<T>& rhs);
    F<T>& operator*=(const T& rhs_scalar);
    // blah
    friend const F<T> operator*(const F<T>& lhs, const T& rhs) { return F(lhs) *= rhs; }
    friend const F<T> operator*(const T& lhs, const F<T>& rhs) { return F(rhs) *= lhs; }
};

In my .cpp file, I have something like:

#include "F.H"

// lots of template<typename T> returntype F<T>::function(args){ body }
template <typename T>
F<T>& F<T>::operator*=(const F<T>& rhs)
{
    // check sizes, etc
    // do multiplication
    return *this;
}
template <typename T>
F<T>& F<T>::operator*=(const T& rhs_scalar)
{
    for(auto &lhs : field_) // field_ is a vector holding values
    {
         lhs *= rhs_scalar;
    }
    return *this;
}

// Non-member parts
template <typename T> operator*(F<T> lhs, const F<T>& rhs)
{ lhs *= rhs; return lhs; }
template <typename T> operator*(const F<T>& lhs, const T& rhs)
{ return F<T>(lhs) *= rhs; }

template class F<double>;
template const F<double> operator*<double>(F<double>, const F<double>&);

This compiles and runs ok, and allows things like:

F<double> test(..);
test *= 2.5; test *= 10; test /= 2.5; test /= 10; // and so on

The question I have is: Can I reduce the number of declarations and definitions of my operators, whilst retaining the ability to implicitly promote an int to a double, etc? Can I rearrange the code so that the friend .. operator*(..) bodies are defined outside of the header file? (I suspect this would involve more specific instantiations in one or both of the header and the cpp file)

(Side note: how? Scott Meyer's Item 46 in 'Effective C++' describes implicit parameter conversion, but it seems like that describes allowing the construction of a temporary object to allow (in that case) Rational(int) * Rational_object_already_created;)

Aucun commentaire:

Enregistrer un commentaire