How do I write a proto transform templated by a function?
Asked Answered
P

1

6

I would like to reuse code by writing a proto transform which is templated by a function pointer:

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

However, the function itself is polymorphic so I do not want to specify its exact signature.

A simplified version of what I would like my code to look like follows (I am using external transforms for a technical reason that I think is unrelated to my current question - I could not get the recursion working without them):

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

That does not compile because there are missing arguments to the appy_func template. Is there a solution?

Polygraph answered 4/3, 2012 at 13:35 Comment(0)
C
3

You have multiple problem in your code:

  • you cannot take a template function pointer without specifying its template parameter as the template won't exist until the function get instanciated.
  • second point, Ret(A,B) is a function type not a function pointer type.
  • function pointer are a bit raw as abstraction goes, same can be achieved by a functor which also solve your problem as a polymorphic fnction object is a single, non template type.
  • final technical point, template transform can't use proto::callable, you have to specialize boost::proto::is_callable explicitly. This is due to a langauge limitation on how the inheritance is detected.

Perusing your pseudo code, I'll go for something like :

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

Type returned by each PFO has to be computed or specified. Beware that A,B can be const/ref qualified and may need stripping before doing type computation.

Sidenote : external_transform are not required at all for recursive rules. I guess point 4 (template callable) was what made it not work.

Christoffer answered 9/3, 2012 at 15:49 Comment(3)
I was hoping to find a solution that will allow the user to specify plus_func and minus_func more concisely (I don't mind complicating the other parts). I understand from your first bullet point that this is not possible - I cannot take a templated free function and turn it into a polymorphic functor. Right?Polygraph
Oh, I see my confusion. Thanks for your help.Polygraph
Note that with C++11, the plus_func could be rather easy to write using auto/decltype and not require the result<> support structure. Now, the Polymorphic Function Object is a rather neat abstraction that helps encapsulate template like functor in a non template structure. In C++03 that's basically the best shot you have and Proto is made to recognize them out of the box.Christoffer

© 2022 - 2024 — McMap. All rights reserved.