Undeclared Identifier with TF1 objects in functions defined with Lambda expressions

I’ve run into an issue with trying to create a function which returns a TF1 object constructed using a lambda expression that references another TF1 object. Line by line, my code runs fine, but putting it in a function breaks it.

Here are two MWE’s showing the issue. The first is my custom code and the second is the lambda expression example straight from the TF1 documentation encapsulated in a function:

TF1* T2(){ // A Paste on CLing attempt to debug undefined identifiers F and F2 for TF1's in a function used in the lambda expression of a new TF1
  Int_t range[] = {16,180};
  TF1* F = new TF1("Background","[0]*exp(-[1]*x)+[2]*exp(-[3]*x)",range[0],range[1]);
  TF1 F2("Background","[0]*exp(-[1]*x)+[2]*exp(-[3]*x)",range[0],range[1]);
  F->SetParName(0,"A"); F->SetParLimits(0,10,1e7);
  F->SetParName(1,"B"); //F->SetParLimits(1,10,1e7);
  F->SetParName(2,"C"); F->SetParLimits(2,10,1e7);
  F->SetParName(3,"D"); //F->SetParLimits(3,10,1e7);
  [&](double* x, Double_t* p){return (*F)(x,&p[0])*2;}; //No errors thrown here
  TF1* FT = new TF1("What","[&](Double_t* x, float* p){return (*F)(x,&p[0])*2;}",range[0],range[1],4);
  TF1* FT2 = new TF1("What","[&](Double_t* x, float* p){return F2(x,&p[0])*2;}",range[0],range[1],4);
  return FT;
TF1 T3(){
  TF1 f1("f1","sin(x)",0,10);
  TF1 f2("f2","cos(x)",0,10);
  TF1 fsum("f1","[&](double *x, double *p){ return p[0]*f1(x) + p[1]*f2(x); }",0,10,2);
  return fsum;

Not only do both functions throw undeclared identifier warnings for F , F2, f2, the second snippet throws an error over f1 which seems to confuse the meaning of *f1(x)

For context, I am ultimately trying to create TF1’s corresponding to background functions, peak shapes, etc. which I will use to perform initial fits (which is why I would like them to be fully-formed TF1 objects with parameter names, limits, etc.). Then, I also want a complete sum of all these functions to use to perform a full fit routine (passing the first fit parameters as starting points). This one roadblock seems like the only issue preventing me from finally getting a proper fit… Am I missing something obvious?

_ROOT Version: 6.10/08
_Platform: Linux
Compiler: Not Provided

The Undeclared Identifier error means you need to add an include.

#include "TF1.h"

I have never worked with lambda expressions before, but since they are C++ function declarations, they must not be put in “” just like a function pointer.

Oh and in your first macro you have “float* p” inside your lamda declarations, but Root expects “Double_t* p”.

The Undeclared Identifier error means you need to add an include.

#include "TF1.h"

Alas, this is being run on the command prompt (copy and paste it in yourself to try it) so everything is already included. If you run the guts of the function, it works, but if you run the function, it doesn’t.

Like this thread, I am using the constructor for TF1 utilizing a lambda function as a string.

My bad, I changed that to debug the undeclared identifier error, but fixing that does not solve the overall issue.

Ok, I did not knew there was a TF1 constructor with a lamba function declared in a string, but this might point to a another possible reason for the error:

The & in the brackets of the lambda function mean that all variables valid in the namespace the lambda function is created in are being made availible inside the function as reference. The problem is that you want to use the TF1 objects F, F2, f1, f2 decladed before in the lambda function. If you use the string declaration the lambda function is actually being created somewhere in the TF1 constructor or a function called by it and there the varaibles F, F2, f1, f2 are not valid so they are not passed to the lambda function and therefore you get an error. I don’t know a way to solve this besides removing the “” and thereby creating the lambda function in a namespace where the objects F, F2, f1, f2 are valid.

If this is not the reason for the error, I have no further ideas. I also tried running your example and it worked after I removed the “”.

So would you consider that a ROOT issue with the string-version’s constructor (worth reporting)? I suppose there’s no loss of usability providing a string versus not a string. It’s still self-contained.

It seems the string-based declaration of lambda TF1 objects requires referencing the const char name* of the constituent TF1’s, not their variable names.

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.