template function with automatically templatized return type.

Discussion in 'C++' started by Daniel Pitts, Jan 30, 2009.

  1. Daniel Pitts

    Daniel Pitts Guest

    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.
    --
    Daniel Pitts' Tech Blog: <http://virtualinfinity.net/wordpress/>
    Daniel Pitts, Jan 30, 2009
    #1
    1. Advertising

  2. Daniel Pitts

    Noah Roberts Guest

    Daniel Pitts wrote:

    > 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.
    Noah Roberts, Jan 30, 2009
    #2
    1. Advertising

  3. Daniel Pitts

    Noah Roberts Guest

    Daniel Pitts wrote:
    > 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.
    Noah Roberts, Jan 30, 2009
    #3
  4. On Jan 30, 6:55 pm, Daniel Pitts
    <> wrote:
    > 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
    Vidar Hasfjord, Jan 31, 2009
    #4
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Damon
    Replies:
    2
    Views:
    11,236
    Damon
    Dec 15, 2003
  2. ma740988
    Replies:
    3
    Views:
    375
    Cy Edmunds
    Nov 6, 2004
  3. mrstephengross
    Replies:
    5
    Views:
    584
    Larry I Smith
    May 18, 2005
  4. Replies:
    3
    Views:
    340
    Victor Bazarov
    Jun 6, 2007
  5. Jean-Louis Leroy
    Replies:
    4
    Views:
    312
    Bo Persson
    Mar 5, 2009
Loading...

Share This Page