Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Return type of template function

Info:

I'm currently trying to learn template metaprogramming (by following this book). One useful example they give is for dimensional analysis. I implemented it as in the book and everything was fine; see here.

My problem is however, I want to use the dimensional analysis framework with mixed types. By this I mean you could have say a scalar with dimensions of mass multiplying a vector with dimensions of acceleration to give a vector force. As it stands in the the link they only work with the same type T for input and output of all operations.

I have a 3-vector class which has all the necessary operations for multiplying with/dividing by scalars, etc. so I would like to do something like

quantity<double,mass> m(1.0);
quantity<vect,acceleration> a(vect(0.0,0.0,-9.81));
quantity<vect,force> f = m*a;

First attempt:

To acheive this I tried exending the examples form the book to handle two different types as inputs to operator* and operator/ however I hit a wall when it comes to the return type.

I know here the return type of double * vect is vect but if they are the other way around vect * double it is still a vect. Worse; in principle the return type could be anything. So I want a way to extend the operator* to something like

template<class T1, class T2, class Dim1, class Dim2>
quantity<X, typename boost::mpl::transform<Dim1,Dim2,boost::mpl::plus<_1,_2> >::type>
operator*(const quantity<T1,Dim1>& q1, const quantity<T2,Dim2>& q2)
{
    return quantity<X,
                    typename boost::mpl::transform<Dim1,Dim2,boost::mpl::plus<_1,_2> >::type>
                   (q1.value()*q2.value());
}

where X is the return type of q1.value()*q2.value() and is deduced at compile time. I tried simply adding another template class T3 to the signature and having it return T3 but it seems it cannot deduce what T3 should be.

Second attempt:

Next I tried using decltype as follows

template<class T1, class T2>
struct return_type
{
    auto mult_f(const T1& a, const T2& b)->decltype(a*b){return a*b;}
    typedef decltype(mult_f) type;
};

template<class T1, class T2, class Dim1, class Dim2>
quantity<typename return_type<T1,T2>::type, typename boost::mpl::transform<Dim1,Dim2,boost::mpl::plus<_1,_2> >::type>
operator*(const quantity<T1,Dim1>& q1, const quantity<T2,Dim2>& q2)
{
    return quantity<typename return_type<T1,T2>::type,
                    typename boost::mpl::transform<Dim1,Dim2,boost::mpl::plus<_1,_2> >::type>
                   (q1.value()*q2.value());
}

However this throws a multitude of incomprehensible compiler errors.

Question:

My question is then, am I using decltype in the correct way but missing some syntax e.g. a typename specifier somewhere? Or; is it even possible to do this this way and if not how is it possible to compute the return type of a function?

Thanks.

like image 984
Dan Avatar asked Jun 19 '12 09:06

Dan


People also ask

What is a template function?

Function templates are similar to class templates but define a family of functions. With function templates, you can specify a set of functions that are based on the same code but act on different types or classes.

Can a function return a type C++?

A function may not return another function, or a built-in array; however it can return pointers to these types, or a lambda, which produces a function object. Except for these cases, a function may return a value of any type that is in scope, or it may return no value, in which case the return type is void .

Is a function template a function?

Function templates. Function templates are special functions that can operate with generic types. This allows us to create a function template whose functionality can be adapted to more than one type or class without repeating the entire code for each type. In C++ this can be achieved using template parameters.


1 Answers

Ok, so first the type return_type<T1,T2>::type is not what you seem to be expecting but is the type of a method, namely T3 (return_type::*)(const T1&, const T2&) with T3 being the type you are expecting. If you want to use an intermediate class, you can use:

template <typename T1, typename T2>
struct return_type
{
  typedef decltype(std::declval<T1>()*std::declval<T2>()) type;
};

But you could also use directly decltype(T1()*T2()) to get the type of the product.

Edit: I edited the code with the suggestion of ildjarn, so no need for default-constructible types. Just don't forget to include <utility>

like image 122
PierreBdR Avatar answered Oct 23 '22 04:10

PierreBdR