user3650284
user3650284

Reputation: 147

Defining conversion from a class to double

I was wondering if there is a way to pull this off, or at least, a better way to do this completely with templates:

template <typename T, typename U>
double sum(const vector<T>& vt, const vector<U>& vu)
{
    // . . .
    double sum = 0;
    for (int i = 0; i < size; ++i)
        sum += convert(vt[i] * vu[i]);
    return sum;
}

T and U are supposed to be numbers like double, int or any other class that supports these operations (I'm new to templates).

Is there any way to get rid of this convert() function (which gets the number member of a specific class) and just write sum += vt[i] * vu[i]?

Upvotes: 1

Views: 100

Answers (4)

LogicStuff
LogicStuff

Reputation: 19607

If you define implicit conversion operators to double (or one to double and other to type that can be promoted to double) for all T and U, vt[i] and vu[i] will be converted to doubles, and the result of multiplication will be double, just as you want.

Example:

class Foo
{
    double value;

public:
    // ...

    operator double() const { return value; }
};

But you must decide what to return.

Upvotes: 3

mksteve
mksteve

Reputation: 13073

I think you are a bit hopeful.

template <typename T, typename U, typename resultType = double >
resultType sum(const vector<T>& vt, const vector<U>& vu)
{
    // . . .
    resultType sum = 0;
    for (size_t i = 0; i < vt.size(); ++i) {
        // two versions of sum - coerced to resultType before and after
        // multiplication
        sum += static_cast<resultType>(vt[i]) * static_cast<resultType>(vu[i]);
        sum += static_cast<resultType>(vt[i] * vu[i]);
    }
    return sum;
}

The 2 versions of sum+= will produce different results. If sum were an integer, then truncation could occur.

In the multiplication between double and int, then type promotion occurs in one, but are normalized in the other.

Update

With resultType = double T and U are double - then the results are the same.

T is integer U is double. T gets promoted to double, the results are the same.

T and U are integer. sum += static_cast<double>( vt[i] * vu[i] ); multiplies the integers, possibly overflowing and returning a different result.

With resultType = int

T and U are double - the result is either the integer truncation of the number, or the integer truncation of the result.

static_cast( 5.3) * static_cast( 3.7); => 15

static_cast( 5.3 * 3.7); => static_cast( 19.61) => 19

T is integer U is double. As above T and U are integer. Both are consistent.

With a class and a

operator double() const { return value; }

as suggested in the other posts, then the first sum += will work, where as the second relies on at least one numeric type, so the compiler can try the explicit double conversion.

With two class then the sum += static_cast<resultType>(vt[i]) * static_cast<resultType>(vu[i]); will succeed in finding the double operator, but the sum += static_cast<resultType>(vt[i]) * static_cast<resultType>(vu[i]); will fail.

Also a function such as

operator *( const class X &lhs, const class U & rhs )
{

    return static_cast<double>(lhs) * static_cast<double>(rhs);
}

Would help the compiler.

Upvotes: 2

Marko Tunjic
Marko Tunjic

Reputation: 1879

Why not use The inner_product() algorithm that is defined in the numeric header?

The inner product algorithm calculates the inner product of two sequences of the same length. Type of value returned is determined by the fourth argument.

#include <numeric>
#include <iostream>
#include <vector>
#include <functional>
#include <iomanip> 

int main()
{
    using namespace std;
    vector<double> a{0, 1.1, 2, 3.1, 4};
    vector<int> b{5, 4, 2, 3, 1};

    double r1 = inner_product(begin(a), end(a), begin(b), 0.0);
    cout << setiosflags(ios::fixed)  << std::setprecision(5)
              << "Inner product of a and b: " << r1 << '\n';


}

Upvotes: 0

Jean-Baptiste Yun&#232;s
Jean-Baptiste Yun&#232;s

Reputation: 36391

If you want to be able to write sum += vt[i] * vu[i]; then the product of T and U must be defined, either by defining an ad-hoc product returning double for these types, by providing a double conversion operator on those types, or some combination of these.

Upvotes: 0

Related Questions