2012-03-04 7 views
6

me gustaría reutilizar el código escribiendo un proto transformar que se templated por un puntero de función:¿Cómo escribo una transformación de proto basada en una función?

template <typename Ret, typename A0, typename A1, Ret func(A0,A1)> 
struct apply_func : proto::callable 
{ 
    // Do something with func 
}; 

Sin embargo, la función en sí es polimórfico, así que no quiero especificar su firma exacta.

Una versión simplificada de cómo me gustaría que se vea mi código (estoy usando transformaciones externas por una razón técnica que creo que no está relacionada con mi pregunta actual - no pude hacer la recursión funcionando sin ellas):

template<typename R, typename A0, typename A1> 
R plus_func(A0 lhs, A1 rhs) { return lhs+rhs; } 

template<typename R, typename A0, typename A1> 
R minus_func(A0 lhs, A1 rhs) { return lhs-rhs; } 

struct my_grammar; 
struct plus_rule : proto::plus<my_grammar, my_grammar> {}; 
struct minus_rule : proto::minus<my_grammar, my_grammar> {}; 

struct my_grammar 
: proto::or_< 
    proto::when<proto::terminal<proto::_>, proto::_value> 
, proto::when<plus_rule, proto::external_transform > 
, proto::when<minus_rule, proto::external_transform > 
> 
{}; 

struct my_external_transforms 
    : proto::external_transforms< 
     proto::when<plus_rule, apply_func<plus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)> 
    , proto::when<minus_rule, apply_func<minus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)> 
    > 
{}; 

Eso no se compila porque faltan argumentos para la plantilla appy_func. ¿Hay una solución?

Respuesta

3

usted tiene problema múltiple en su código:

  • no se puede tomar un puntero de función de plantilla sin especificar su parámetro de plantilla como la plantilla no existirá hasta que la función get instanciado.
  • segundo punto, Ret (A, B) es un tipo de función, no un tipo de puntero a función.
  • puntero a la función son un poco primas como va la abstracción, lo mismo se puede lograr mediante un functor que también resuelve su problema ya que un objeto de fusión polimórfica es un tipo único, sin plantilla.
  • punto técnico final, transformación de plantilla no puede usar proto :: llamable, debe especializar boost :: proto :: is_callable explícitamente. Esto se debe a una limitación de idioma sobre cómo se detecta la herencia.

Examinando el código de pseudo, voy a ir por algo así como:

struct plus_func 
{ 
    template<class Sig> struct result; 

    template<class This,class A, class B> 
    struct result<This(A,B)> 
    { 
    typedef /*whatever*/ type; 
    }; 

    template<class A, class B> 
    typename result<plus_func(A const&,B const&)>::type 
    plus_func(A const& lhs, B const& rhs) 
    { 
    return lhs+rhs; 
    } 
}; 

struct minus_func 
{ 
    template<class Sig> struct result; 

    template<class This,class A, class B> 
    struct result<This(A,B)> 
    { 
    typedef /*whatever*/ type; 
    }; 

    template<class A, class B> 
    typename result<minus_func(A const&,B const&)>::type 
    plus_func(A const& lhs, B const& rhs) 
    { 
    return lhs-rhs; 
    } 
}; 

struct my_grammar; 
struct plus_rule : proto::plus<my_grammar, my_grammar> {}; 
struct minus_rule : proto::minus<my_grammar, my_grammar> {}; 

struct my_grammar 
: proto::or_< 
    proto::when<proto::terminal<proto::_>, proto::_value> 
, proto::when<plus_rule, proto::external_transform > 
, proto::when<minus_rule, proto::external_transform > 
> 
{}; 

struct my_external_transforms 
    : proto::external_transforms< 
     proto::when<plus_rule, apply_func<plus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)> 
    , proto::when<minus_rule, apply_func<minus_func>(my_grammar(proto::_left),my_grammar(proto::_right), proto::_state)> 
    > 
{}; 

tipo devuelto por cada PFO tiene que ser calculado o especificado. Tenga en cuenta que A, B puede ser const/ref calificado y puede necesitar ser eliminado antes de realizar un cálculo de tipo.

Sidenote: external_transform no son necesarios en absoluto para las reglas recursivas. Supongo que el punto 4 (plantilla invocable) fue lo que hizo que no funcionara.

+0

Estaba esperando encontrar una solución que permita al usuario especificar más_func y menos_func de manera más concisa (no me importa complicar las otras partes). Desde su primer punto, entiendo que esto no es posible. No puedo tomar una función libre de plantillas y convertirla en un functor polimórfico. ¿Derecha? –

+0

Oh, veo mi confusión. Gracias por tu ayuda. –

+0

Tenga en cuenta que con C++ 11, el plus_func podría ser bastante fácil de escribir usando auto/decltype y no requeriría la estructura de soporte result <>. Ahora, el Objeto de función polimórfica es una abstracción bastante ordenada que ayuda a encapsular plantilla como functor en una estructura sin plantilla. En C++ 03 es básicamente la mejor toma que tienes y Proto está hecho para reconocerlos de la caja. –

Cuestiones relacionadas