TF1 from Member Function in Compiled Code

Hi, I have some objects of a class that inherits from ROOT::Math::Interpolator with an ::Eval method that has the right signature to make TF1 objects: Double_t MyInterpolator::Eval(Double_t *, Double_t *). In CINT, I can do this:

MyInterpolator * myp = make_interpolator();
TF1 f1("f1",myp,&MyInterpolator::Eval,xmin,xmax,0,"MyInterpolator","Eval");

and it works fine. I wanted to automate some of this and wrote a function:

TF1 makeTF1(MyInterpolator * myp,Double_t xmin = -0.7,Double_t xmax = -0.7)
{
  TF1 f1("f1",myp,&MyInterpolator,xmin,xmax,0,"MyInterpolator","Eval");
  return f1;
}

but I get a errors about no available constructor:

/Users/jfcaron/Projects/Proto2BeamTest2/./t2x.C:188:7: error: no matching constructor for initialization of 'TF1'
  TF1 f1("f1",myp,&MyInterpolator::Eval,lims.first,lims.second,0,"MyInterpolator","Eval");
      ^  ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
/opt/local/include/root/TF1.h:190:4: note: candidate constructor not viable: no overload of 'Eval' matching 'void *' for 3rd argument
   TF1(const char *name, void *ptr, void *,Double_t xmin, Double_t xmax, Int_t npar, const char *className, const char *methodName = 0);
   ^
/opt/local/include/root/TF1.h:156:4: note: candidate template ignored: couldn't infer template argument 'MemFn'
   TF1(const char *name, const  PtrObj& p, MemFn memFn, Double_t xmin, Double_t xmax, Int_t npar, const char * = 0, const char * = 0) :

(and more lines with constructors having the wrong number of arguments). I tried many variations like doing a (void*) cast, but nothing worked until I looked up member function pointers. Following some instructions from a blog, I ended up making this:

typedef Double_t (MyInterpolator::*FNMETHOD) (Double_t *, Double_t *) const;

TF1 makeTF1(MyInterpolator * myp,Double_t xmin = -0.7,Double_t xmax = -0.7)
{
  FNMETHOD m = &MyInterpolator::Eval;
  TF1 f1("f1",myp,m,xmin,xmax,0,"MyInterpolator","Eval");
  return f1;
}

I am happy that it works, but I am less happy that it took a long time to get this working. What is the essential difference? It looks like I am just giving the member pointer a temporary name “m” instead of naming it directly in the constructor, why does the TF1 care? How does CINT figure out to do the right thing?

Jean-François

HI,

I have not understood if you are compiling the code using AClic or using in interpreted mode. If you use CINT in interpreted mode, it just uses the object pointer, so actually you don’t need to pass the member function pointer. The member function is found by its name. However, in C++ you need to pass the member function pointer. You automated way should work, but you need to write correctly

Best Regards

Lorenzo

Sorry I wasn’t clear. I first was making the TF1 from the member functions using CINT (the first code block in my original post), and it worked fine.

Then I tried writing a function in a file that I compiled with ACLiC (the second code block), which fails with the error about no available constructor.

After doing a typedef, what seems to be the same function now compiles properly with ACLiC (the last code block in my original post).

The part I do not understand is why is the typedef necessary? The syntax in the code that compiles fine is the same as in the one that gave the error, aside from the typedef. The typedef just gives &MyInterpolator::Eval a name “m”, so why doesn’t it work if I write &MyInterpolator::Eval directly in the third argument of the TF1 constructor instead of m?

Jean-François

Hi,

Yes it seems strange to me too. Can you please upload the minimal code, so I can try it also with a different compiler version

Thank you

Lorenzo

Unfortunately minimal code seems to work as expected - the makeTF1 function compiles and works with the same syntax as CINT. Perhaps it is related to how I created the MyInterpolator class or something. Since I fixed the immediate problem with the typedef, I will not look into it more.

Jean-François