2012-06-19 16 views
6

Info:tipo devuelto de función de plantilla

Actualmente estoy tratando de aprender metaprogramming plantilla (siguiendo this book). Un ejemplo útil que dan es para el análisis dimensional. Lo implementé como en el libro y todo estuvo bien; see here.

Mi problema, sin embargo, es que quiero utilizar el marco de análisis dimensional con tipos mixtos. Con esto quiero decir que podrías haber dicho un escalar con dimensiones de masa multiplicando un vector con dimensiones de aceleración para dar una fuerza vectorial. Tal como está en el enlace, solo funcionan con el mismo tipo T para la entrada y la salida de todas las operaciones.

tengo una clase 3-vector que tiene todas las operaciones necesarias para la multiplicación con/dividiendo por escalares, etc por lo que me gustaría hacer algo como

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

Primer intento:

Para lograr esto traté de ejemplificar los ejemplos del libro para manejar dos tipos diferentes como entradas a operator* y operator/, sin embargo, choqué contra una pared cuando se trata del tipo de devolución.

Yo sé que aquí el tipo de retorno de double * vect es vect pero si son al revés vect * double sigue siendo un vect. Peor; en principio, el tipo de devolución podría ser cualquier cosa. Así que quiero una manera de extender la operator* a algo así como

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()); 
} 

donde X es el tipo de retorno de q1.value()*q2.value() y se deduce en tiempo de compilación. Intenté simplemente agregar otra clase de plantilla T3 a la firma y hacer que devuelva T3, pero parece que no puede deducir qué debería ser T3.

Segundo intento:

siguiente que trató de usar decltype de la siguiente manera

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()); 
} 

Sin embargo, esto arroja una multitud de errores de compilación incomprensibles.

Pregunta:

Mi pregunta es, entonces, estoy usando decltype de la manera correcta pero falta alguna sintaxis, por ejemplo, un especificador typename en alguna parte? O; ¿Es posible hacerlo de esta manera y si no es posible calcular el tipo de retorno de una función?

Gracias.

Respuesta

6

Ok, así que primero el tipo return_type<T1,T2>::type no es lo que parece estar esperando, pero es el tipo de un método, a saber T3 (return_type::*)(const T1&, const T2&) con T3 ser el tipo que está esperando.Si desea utilizar una clase intermedia, puede utilizar:

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

Pero también se puede utilizar directamente decltype(T1()*T2()) para obtener el tipo de producto.

Editar: edité el código con la sugerencia de ildjarn, por lo que no hay necesidad de tipos predefinibles. Simplemente no se olvide de incluir <utility>

+0

Sí, podía decir por la salida del compilador que obtenía la firma de la función completa. No sé por qué estaba complicando tanto las cosas, tu ejemplo compila bien :) El requisito de constructor predeterminado no es un problema para mí aquí. – Dan

+2

@Dan: tenga en cuenta que el libro se escribió antes de la disponibilidad de C++ 11 y 'decltype' /' auto', lo que hizo que las cosas ** mucho ** fueran más complicadas. –

+2

Reemplace 'decltype (T1() * T2())' con 'decltype (std :: declval () * std :: declval ())' y ya no necesita construcciones predeterminadas. – ildjarn

Cuestiones relacionadas