TF1 constructor with custom class - Broken with XCode 9.0

Dear ROOTers,
in our experiment software we have a piece of code almost identical to the following snippet:

#include <iostream>
#include <vector>

#include "TROOT.h"
#include "TMath.h"
#include "TF1.h"

class MyClass : public TObject {
public:
  MyClass();
  ~MyClass();

  double operator()(double* x, double*p){ return x[0]*x[0]; };

  std::vector<float> Generate(int nevents){
    std::vector<float> vec;
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
    f->SetNpx(4000);
    for(int i=0;i<nevents;i++){
      vec.push_back(f->GetRandom());
    }
    delete f;
    return vec;
  }

};

int main(){

  MyClass* testobj;

  std::vector<float> vec = testobj->Generate(100);

  for(int i=0; i<vec.size(); i++){
    std::cout << vec[i] << std::endl;
  }

}

which compiled just fine until I accidentally (curse you, Apple!) upgraded XCode to version 9.0.
After checking out commit 9339de9e64 from the master branch (where the fix for XCode 9 was introduced) I recompiled ROOT. Now suddenly the piece of code above does not compile anymore

1 ✗ vformato@formato-pc0 /Volumes/AMS_Disk/test/test_TF1
 17:42 $ g++ -o test -I `root-config --cflags` test.C
In file included from test.C:6:
/Users/vformato/root/include/TF1.h:370:101: error: type 'MyClass *' cannot be used prior to '::' because it has no
      members
      using Fnc_t = typename ROOT::Internal::GetFunctorType<decltype(ROOT::Internal::GetTheRightOp(&Func::oper...
                                                                                                    ^
test.C:17:18: note: in instantiation of function template specialization 'TF1::TF1<MyClass *>' requested here
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
                 ^
In file included from test.C:6:
In file included from /Users/vformato/root/include/TF1.h:35:
/Users/vformato/root/include/Math/ParamFunctor.h:125:17: error: no matching function for call to object of type
      'MyClass'
         return (*f)((T*)x, (double*)p);
                ^~~~
/Users/vformato/root/include/Math/ParamFunctor.h:95:45: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::FuncEvaluator<MyClass *,
      int>::EvalConst' requested here
      return FuncEvaluator<Func, EvalType>::EvalConst(fFunc,x,p);
                                            ^
/Users/vformato/root/include/Math/ParamFunctor.h:73:4: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::operator()' requested here
   ParamFunctorHandler(const Func & fun) : fFunc(fun) {}
   ^
/Users/vformato/root/include/Math/ParamFunctor.h:304:17: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::ParamFunctorHandler' requested
      here
      fImpl(new ParamFunctorHandler<ParamFunctorTempl<T>,Func>(f) )
                ^
/Users/vformato/root/include/TF1.h:372:51: note: in instantiation of function template specialization
      'ROOT::Math::ParamFunctorTempl<int>::ParamFunctorTempl<MyClass *>' requested here
      fFunctor = new TF1FunctorPointerImpl<Fnc_t>(ROOT::Math::ParamFunctorTempl<Fnc_t>(f));
                                                  ^
test.C:17:18: note: in instantiation of function template specialization 'TF1::TF1<MyClass *>' requested here
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
                 ^
test.C:13:10: note: candidate function not viable: no known conversion from 'int *' to 'double *' for 1st argument
  double operator()(double* x, double*p){ return x[0]*x[0]; };
         ^
In file included from test.C:6:
In file included from /Users/vformato/root/include/TF1.h:35:
/Users/vformato/root/include/Math/ParamFunctor.h:121:17: error: no matching function for call to object of type
      'MyClass'
         return (*f)(x, p);
                ^~~~
/Users/vformato/root/include/Math/ParamFunctor.h:91:45: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::FuncEvaluator<MyClass *,
      int>::Eval' requested here
      return FuncEvaluator<Func, EvalType>::Eval(fFunc,x,p);
                                            ^
/Users/vformato/root/include/Math/ParamFunctor.h:73:4: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::operator()' requested here
   ParamFunctorHandler(const Func & fun) : fFunc(fun) {}
   ^
/Users/vformato/root/include/Math/ParamFunctor.h:304:17: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::ParamFunctorHandler' requested
      here
      fImpl(new ParamFunctorHandler<ParamFunctorTempl<T>,Func>(f) )
                ^
/Users/vformato/root/include/TF1.h:372:51: note: in instantiation of function template specialization
      'ROOT::Math::ParamFunctorTempl<int>::ParamFunctorTempl<MyClass *>' requested here
      fFunctor = new TF1FunctorPointerImpl<Fnc_t>(ROOT::Math::ParamFunctorTempl<Fnc_t>(f));
                                                  ^
test.C:17:18: note: in instantiation of function template specialization 'TF1::TF1<MyClass *>' requested here
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
                 ^
test.C:13:10: note: candidate function not viable: no known conversion from 'int *' to 'double *' for 1st argument
  double operator()(double* x, double*p){ return x[0]*x[0]; };
         ^
3 errors generated.

Being paranoid I also checked out the HEAD of the master branch and the problem is still there. Googling around I found out this stackoverflow thread that seems to be kinda related, even if I don’t understand how this didn’t happen with the previous clang version.

Any idea how to solve this?

Cheers,
Valerio

Try:
double operator() (const double *x, const double */*p*/) { return (x[0] * x[0]); }

BTW. Warning: “testobj” is used uninitialized in “main”.

Hi Wile,
unfortunately no joy. I’ve updated the snippet but I still get the same error messages.

#include <iostream>
#include <vector>

#include "TROOT.h"
#include "TMath.h"
#include "TF1.h"

class MyClass : public TObject {
public:
  MyClass();
  ~MyClass();

  double operator()(double* x, double* /*p*/){ return (x[0]*x[0]); };

  std::vector<float> Generate(int nevents){
    std::vector<float> hits;
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
    f->SetNpx(4000);
    for(int i=0;i<nevents;i++){
      hits.push_back(f->GetRandom());
    }
    delete f;
    return hits;
  }

};

int main(){

  MyClass* testobj = new MyClass();

  std::vector<float> vec = testobj->Generate(100);

  for(int i=0; i<vec.size(); i++){
    std::cout << vec[i] << std::endl;
  }

}

Try (copy and paste the line below):
double operator() (const double *x, const double */*p*/) { return (x[0] * x[0]); }

My bad I missed the const declaration. Still no joy, this time I actually copypasted that line

0 ✓ vformato@formato-pc0 /Volumes/AMS_Disk/test/test_TF1
 10:29 $ g++ -o test -I `root-config --cflags` test.C
In file included from test.C:6:
/Users/vformato/root/include/TF1.h:370:101: error: type 'MyClass *' cannot be used prior to '::' because it has no
      members
      using Fnc_t = typename ROOT::Internal::GetFunctorType<decltype(ROOT::Internal::GetTheRightOp(&Func::oper...
                                                                                                    ^
test.C:19:18: note: in instantiation of function template specialization 'TF1::TF1<MyClass *>' requested here
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
                 ^
In file included from test.C:6:
In file included from /Users/vformato/root/include/TF1.h:35:
/Users/vformato/root/include/Math/ParamFunctor.h:125:17: error: no matching function for call to object of type
      'MyClass'
         return (*f)((T*)x, (double*)p);
                ^~~~
/Users/vformato/root/include/Math/ParamFunctor.h:95:45: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::FuncEvaluator<MyClass *,
      int>::EvalConst' requested here
      return FuncEvaluator<Func, EvalType>::EvalConst(fFunc,x,p);
                                            ^
/Users/vformato/root/include/Math/ParamFunctor.h:73:4: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::operator()' requested here
   ParamFunctorHandler(const Func & fun) : fFunc(fun) {}
   ^
/Users/vformato/root/include/Math/ParamFunctor.h:304:17: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::ParamFunctorHandler' requested
      here
      fImpl(new ParamFunctorHandler<ParamFunctorTempl<T>,Func>(f) )
                ^
/Users/vformato/root/include/TF1.h:372:51: note: in instantiation of function template specialization
      'ROOT::Math::ParamFunctorTempl<int>::ParamFunctorTempl<MyClass *>' requested here
      fFunctor = new TF1FunctorPointerImpl<Fnc_t>(ROOT::Math::ParamFunctorTempl<Fnc_t>(f));
                                                  ^
test.C:19:18: note: in instantiation of function template specialization 'TF1::TF1<MyClass *>' requested here
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
                 ^
test.C:14:10: note: candidate function not viable: no known conversion from 'int *' to 'const double *' for 1st
      argument
  double operator() (const double *x, const double */*p*/) { return (x[0] * x[0]); }
         ^
In file included from test.C:6:
In file included from /Users/vformato/root/include/TF1.h:35:
/Users/vformato/root/include/Math/ParamFunctor.h:121:17: error: no matching function for call to object of type
      'MyClass'
         return (*f)(x, p);
                ^~~~
/Users/vformato/root/include/Math/ParamFunctor.h:91:45: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::FuncEvaluator<MyClass *,
      int>::Eval' requested here
      return FuncEvaluator<Func, EvalType>::Eval(fFunc,x,p);
                                            ^
/Users/vformato/root/include/Math/ParamFunctor.h:73:4: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::operator()' requested here
   ParamFunctorHandler(const Func & fun) : fFunc(fun) {}
   ^
/Users/vformato/root/include/Math/ParamFunctor.h:304:17: note: in instantiation of member function
      'ROOT::Math::ParamFunctorHandler<ROOT::Math::ParamFunctorTempl<int>, MyClass *>::ParamFunctorHandler' requested
      here
      fImpl(new ParamFunctorHandler<ParamFunctorTempl<T>,Func>(f) )
                ^
/Users/vformato/root/include/TF1.h:372:51: note: in instantiation of function template specialization
      'ROOT::Math::ParamFunctorTempl<int>::ParamFunctorTempl<MyClass *>' requested here
      fFunctor = new TF1FunctorPointerImpl<Fnc_t>(ROOT::Math::ParamFunctorTempl<Fnc_t>(f));
                                                  ^
test.C:19:18: note: in instantiation of function template specialization 'TF1::TF1<MyClass *>' requested here
    TF1 *f = new TF1("temp_f",this,0,4000,0,"MyClass");
                 ^
test.C:14:10: note: candidate function not viable: no known conversion from 'int *' to 'const double *' for 1st
      argument
  double operator() (const double *x, const double */*p*/) { return (x[0] * x[0]); }
         ^
3 errors generated.

Well, I don’t think it’ll help, but give it a try:
Double_t operator() (const Double_t *x, const Double_t */*p*/) { return (x[0] * x[0]); }

And another thing to try … remove “public TObject” (which is not needed at all here).

You’re right, it didn’t help.

Neither did this, and I agree it’s not needed here, but it actually is in our experiment software.

How about:

TF1 *f = new TF1("temp_f", *this, 0., 4000., 0);

Ok that actually made it compile, but I’m somehow worried, has the signature for the TF1 constructor changed? Because it used to be that you could pass a pointer to the object, instead of the actual reference (at least, the code used to compile without problems).

Thanks anyways

Hi, @valerio.formato

You are right, it’s a bug I introduced while refactoring! It should be fixed with this PR: https://github.com/root-project/root/pull/1123

Will notify you once it is merged. Thanks!

@valerio.formato Merged!

1 Like

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