[math] Use std::function in ROOT::Math::ParamFunctor - #23211
Conversation
2867e5e to
3b30a35
Compare
Test Results 19 files 19 suites 3d 5h 7m 53s ⏱️ For more details on these failures, see this check. Results for commit 0480d6b. ♻️ This comment has been updated with latest results. |
3b30a35 to
efb4d48
Compare
hageboeck
left a comment
There was a problem hiding this comment.
Thanks for the changes! It looks like now we can go even further.
efb4d48 to
81f063b
Compare
`ParamFunctor` was still carrying the hand-rolled type erasure that the other `ROOT::Math` functors got rid of in 6c68bbd and a24465f: a `ParamFunctionBase` interface, `ParamFunctorHandler` and `ParamMemFunHandler` implementations of it, three `FuncEvaluator` partial specialisations to tell pointer types apart, a manual `Clone()`, a raw owning `Impl *` with hand-written copy constructor, assignment operator and destructor, and about 40 lines of commented-out code. All of that is what `std::function` does, and the class already had a `std::function` constructor sitting next to it. Store a single `std::function<T(const T *, const double *)>` instead and let the compiler generate the copy operations. The three callable shapes the `FuncEvaluator` specialisations used to dispatch on are kept by normalising them in one `Adapt()` helper: a callable taking const pointers is stored as is, a callable insisting on non-const pointers (the classic `T (T *x, double *p)` signature) gets them cast for it, and a pointer to a callable object is called through without taking ownership of it. That makes the separate `FreeFunc` constructor redundant, since `Adapt()` already normalises a free function pointer, so it goes. Nothing in ROOT converted a free function to a `ParamFunctor` implicitly. The `std::function` constructor stays implicit, on the other hand, because PyROOT needs it: cppyy binds a Python-side callable to the `TF1(const char *, ROOT::Math::ParamFunctor, ...)` overload through that conversion, and `tutorials/math/fit/fitNormSum.py` fails to find a viable overload without it. Calling a `ParamFunctor` is unchanged, and so is constructing one, with one further exception: the constructor from an object and one of its member functions now takes a plain `Obj *` rather than a `const PtrObj &` that only had to be dereferenceable. Every caller passes a raw pointer, and spelling that out rejects at the signature what used to fail inside the handler. The removed `GetImpl()` and `SetFunction()` were only handles on the deleted `ParamFunctionBase` and had no callers. 🤖 Done with the help of AI
81f063b to
0480d6b
Compare
|
Thank you @hageboeck for your next two suggestions! I have implemented them both. Once again, and additional |
hageboeck
left a comment
There was a problem hiding this comment.
OK, very nice!
The CI is full of checkout-related failures, so better double check, but the code seems to have improved a lot!
ParamFunctorwas still carrying the hand-rolled type erasure that the otherROOT::Mathfunctors got rid of in 6c68bbd and a24465f: aParamFunctionBaseinterface,ParamFunctorHandlerandParamMemFunHandlerimplementations of it, threeFuncEvaluatorpartial specialisations to tell pointer types apart, a manualClone(), a raw owningImpl *with hand-written copy constructor, assignment operator and destructor, and about 40 lines of commented-out code.All of that is what
std::functiondoes, and the class already had astd::functionconstructor sitting next to it. Store a singlestd::function<T(const T *, const double *)>instead and let the compiler generate the copy operations.The three callable shapes the
FuncEvaluatorspecialisations used to dispatch on are kept by normalising them in oneAdapt()helper: a callable taking const pointers is stored as is, a callable insisting on non-const pointers (the classicT (T *x, double *p)signature) gets them cast for it, and a pointer to a callable object is called through without taking ownership of it.Constructing and calling a
ParamFunctoris unchanged. The removedGetImpl()andSetFunction()were only handles on the deletedParamFunctionBaseand had no callers.The
<iostream>include went away with the code that needed it; two files that were picking it up transitively viaTF1.hnow include it themselves.🤖 Done with the help of AI