Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Could this templated syntax be improved?

I have this template method:

template <class SomeLhs, class SomeRhs, 
          ResultType (SomeLhs::*callback)(SomeRhs&)>
void Add() {
  struct Local {
    static ResultType Trampoline(BaseLhs& lhs, BaseRhs& rhs) {
      return (static_cast<SomeLhs&>(lhs).*callback)(static_cast<SomeRhs&>(rhs));
    }
  };
  _back_end.template Add<SomeLhs,SomeRhs>(&Local::Trampoline);
}

Currently I'm calling it like this:

tracker.Add<Quad, Multi, &Quad::track>();
tracker.Add<Quad, Singl, &Quad::track>();
tracker.Add<Sext, Multi, &Sext::track>();
...

It is working fine, but I don't like to have to repeat two times the name of class SomeLhs. Is there a way to avoid that?

For people who may have recognized it: yes, this is related to the BasicFastDispatcher of Alexandrescu, in particular I'm writing a front end to operate with member functions.

like image 651
DarioP Avatar asked Jun 27 '14 11:06

DarioP


1 Answers

I don't think it can't be improved particularly, which is unfortunate as I'd love to find a way to do this.

Template type deduction is only possible for function template arguments and you need to pass in the non-type member function pointer at compile time in order for it to be treated as a name rather than a varying quantity. Which means having to specify all the args.

i.e. you can do this:

template <class SomeLhs, class SomeRhs>
void Add(ResultType (SomeLhs::*callback)(SomeRhs&)) {
  ...
}
// nice syntax:
tracker.Add(&Sext::track);
// But ugly for overloaded functions, a cast is needed.
// p.s. not sure this is exactly the right syntax without compiling it.
tracker.Add((ResultType (Quad::*)(Multi&) &Quad::track);

But then you have an actual pointer that cannot subsequently be used as a template parameter.

The only thing I think you could do is to use a macro, though it is arguable if it really improves syntax here. I'd say it probably adds an unnecessary level of obfuscation.

e.g.

#define TMFN_ARGS(C, M, P1) C, P1, &C::M
tracker.Add<TMFN_ARGS(Quad, track, Multi)>();

EDIT:

However, if the name of the function is Always 'track', you could do something along the following lines:

template <typename C, typename P1>
void AddTrack() {
   Add<C, P1, &C::track>();
}
tracker.AddTrack<Quad, Multi>();
like image 163
Pete Avatar answered Nov 18 '22 08:11

Pete