Skip to content

[math] Use std::function in ROOT::Math::ParamFunctor - #23211

Merged
guitargeek merged 1 commit into
root-project:masterfrom
guitargeek:paramfunctor-std-function
Sep 7, 2026
Merged

[math] Use std::function in ROOT::Math::ParamFunctor#23211
guitargeek merged 1 commit into
root-project:masterfrom
guitargeek:paramfunctor-std-function

Conversation

@guitargeek

Copy link
Copy Markdown
Contributor

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.

Constructing and calling a ParamFunctor is unchanged. The removed GetImpl() and SetFunction() were only handles on the deleted ParamFunctionBase and had no callers.

The <iostream> include went away with the code that needed it; two files that were picking it up transitively via TF1.h now include it themselves.

🤖 Done with the help of AI

Comment thread hist/hist/src/TEfficiency.cxx Outdated
Comment thread tutorials/analysis/unfold/testUnfold2.C Outdated
Comment thread math/mathcore/inc/Math/ParamFunctor.h Outdated
Comment thread math/mathcore/inc/Math/ParamFunctor.h Outdated
Comment thread math/mathcore/inc/Math/ParamFunctor.h Outdated
Comment thread math/mathcore/inc/Math/ParamFunctor.h Outdated
@github-actions

github-actions Bot commented Sep 1, 2026

Copy link
Copy Markdown

Test Results

    19 files      19 suites   3d 5h 7m 53s ⏱️
 3 877 tests  3 876 ✅  0 💤 1 ❌
64 855 runs  64 816 ✅ 38 💤 1 ❌

For more details on these failures, see this check.

Results for commit 0480d6b.

♻️ This comment has been updated with latest results.

@couet
couet removed their request for review September 3, 2026 08:48
@guitargeek
guitargeek force-pushed the paramfunctor-std-function branch from 3b30a35 to efb4d48 Compare September 3, 2026 10:34

@hageboeck hageboeck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the changes! It looks like now we can go even further.

Comment thread math/mathcore/inc/Math/ParamFunctor.h Outdated
Comment thread math/mathcore/inc/Math/ParamFunctor.h Outdated
@guitargeek
guitargeek force-pushed the paramfunctor-std-function branch from efb4d48 to 81f063b Compare September 7, 2026 07:41
`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
@guitargeek
guitargeek force-pushed the paramfunctor-std-function branch from 81f063b to 0480d6b Compare September 7, 2026 08:04
@guitargeek

Copy link
Copy Markdown
Contributor Author

Thank you @hageboeck for your next two suggestions! I have implemented them both. Once again, and additional std::enable_if was required to avoid that the templated constructor beats the copy constructor and the std::function constructor, but that was it.

@hageboeck hageboeck left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OK, very nice!

The CI is full of checkout-related failures, so better double check, but the code seems to have improved a lot!

@guitargeek
guitargeek merged commit 443ae43 into root-project:master Sep 7, 2026
28 of 35 checks passed
@guitargeek
guitargeek deleted the paramfunctor-std-function branch September 7, 2026 11:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants