template function with automatically templatized return type.

D

Daniel Pitts

I have a Vector (as in math vector) template class.

template <typename component_t>
class Vector { /*...*/ };

It defines what you might expect for operators: =, [] +, -, * (as a
scalar multiply), /, etc...

I have some type which the result of (x*x) is not the same type as x.

OtherType operator*(const SomeType &, const SomeType &).

I would like to be able to define a generic operator* for Vector such
that the following works:

const Vector<OtherType> n = Vector<SomeType>() * SomeType();

I tried

template<typename component_in_t,
typename component_out_t, typename scalar_t>
Vector<component_out_t> operator *(const Vector<component_in_t> &in,
scalar_t scalar) {
Vector<component_out_t> result;
for (int i = 0; i < dimensions; ++i) {
result = in*scalar;
}
return result;
}

But my compiler can't infer component_out_t.

Is there any way to do this?

Thanks,
Daniel.
 
N

Noah Roberts

Daniel said:
I tried

template<typename component_in_t,
typename component_out_t, typename scalar_t>
Vector<component_out_t> operator *(const Vector<component_in_t> &in,
scalar_t scalar) {
Vector<component_out_t> result;
for (int i = 0; i < dimensions; ++i) {
result = in*scalar;
}
return result;
}

But my compiler can't infer component_out_t.


How could it?
Is there any way to do this?

No.
 
N

Noah Roberts

Daniel said:
I have a Vector (as in math vector) template class.

template <typename component_t>
class Vector { /*...*/ };

It defines what you might expect for operators: =, [] +, -, * (as a
scalar multiply), /, etc...

I have some type which the result of (x*x) is not the same type as x.

OtherType operator*(const SomeType &, const SomeType &).

I would like to be able to define a generic operator* for Vector such
that the following works:

const Vector<OtherType> n = Vector<SomeType>() * SomeType();

Actually, there probably is a way to do this but it's going to be some
sort of magic that I don't know. Clearly not what you've started with.
You need to somehow retrieve the OtherType type from metafunction
programming so that you can tell the operator * for vector * type what
to return.

So, get learning MPL and dig through the boost::type_traits library that
will be part of the next standard.

One easy method, but one that doesn't scale well, would be to create a
trait for "sometype" that is like "multiplication_type<X>" that returns
OtherType for SomeType.
 
V

Vidar Hasfjord

I have a Vector (as in math vector) template class.

template <typename component_t>
class Vector { /*...*/ };

It defines what you might expect for operators: =, [] +, -, * (as a
scalar multiply), /, etc...

I have some type which the result of (x*x) is not the same type as x.

OtherType operator*(const SomeType &, const SomeType &).

I would like to be able to define a generic operator* for Vector such
that the following works:

const Vector<OtherType> n = Vector<SomeType>() * SomeType();

I tried

template<typename component_in_t,
         typename component_out_t, typename scalar_t>
Vector<component_out_t> operator *(const Vector<component_in_t> &in,
                                    scalar_t scalar) {
    Vector<component_out_t> result;
    for (int i = 0; i < dimensions; ++i) {
      result = in*scalar;
    }
    return result;

}

But my compiler can't infer component_out_t.

Is there any way to do this?


Yes. While C++ doesn't directly support overloading on return type,
you can achieve the effect by returning a proxy that has conversion
operators for the required return types. The conversion operator then
performs the operation. For example:

const int dimensions = 2;

template <typename T>
struct Vector
{
T v_ [dimensions];
T& operator [] (int i) {return v_ ;}
const T& operator [] (int i) const {return v_ ;}
};

template <typename T1, typename T2>
struct VectorMultiplication
{
const Vector <T1>* v_;
T2 s_;

VectorMultiplication (const Vector <T1>& v, T2 s)
: v_ (&v), s_ (s) {}

template <typename T3>
operator Vector <T3> () const {
Vector <T3> r = {};
for (int i = 0; i < dimensions; ++i)
r = (*v_) * s_;
return r;
}
};

template <typename T1, typename T2>
VectorMultiplication <T1, T2>
operator * (const Vector <T1>& v, T2 s)
{
return VectorMultiplication <T1, T2> (v, s);
}

// Test

#include <iostream>
#include <iterator>
#include <algorithm>

using namespace std;

template <typename T>
ostream& operator << (ostream& os, const Vector <T>& v)
{
copy (&v [0], &v [0] + dimensions,
ostream_iterator <T> (os, " "));
return os;
}

void test_overloaded_return_type ()
{
Vector <short> v = {1, 2};
cout << v << endl; // 1 2

Vector <int> r = v * 2;
cout << r << endl; // 2 4
}

You can extend the proxy to a full expression template to optimize
your vector operations. Look up "expression template" for more
information.

Regards,
Vidar Hasfjord
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,991
Messages
2,570,212
Members
46,800
Latest member
Tobi1987

Latest Threads

Top