diff --git a/hist/hist/inc/TF1.h b/hist/hist/inc/TF1.h index f830669f71822..14178a9e37df5 100644 --- a/hist/hist/inc/TF1.h +++ b/hist/hist/inc/TF1.h @@ -22,8 +22,9 @@ ////////////////////////////////////////////////////////////////////////// #include "RConfigure.h" -#include #include +#include +#include #include #include #include @@ -709,7 +710,14 @@ namespace ROOT { #endif { f->fType = TF1::EFType::kTemplScalar; - f->fFunctor.reset(new TF1::TF1FunctorPointerImpl(ROOT::Math::ParamFunctorTempl(func))); + if constexpr (std::is_invocable_r_v) { + auto wrapper = [func, npar = f->fNpar, ndim = f->fNdim](const double *x, const double *p) -> double { + return func(x, static_cast(ndim), p, static_cast(npar)); + }; + f->fFunctor = std::make_unique>(ROOT::Math::ParamFunctorTempl(wrapper)); + } else { + f->fFunctor.reset(new TF1::TF1FunctorPointerImpl(ROOT::Math::ParamFunctorTempl(func))); + } } f->fParams = std::make_unique(f->fNpar); @@ -727,7 +735,14 @@ namespace ROOT { #endif { f->fType = TF1::EFType::kTemplScalar; - f->fFunctor.reset(new TF1::TF1FunctorPointerImpl(ROOT::Math::ParamFunctorTempl(func))); + if constexpr (std::is_invocable_r_v) { + auto wrapper = [func, npar = f->fNpar, ndim = f->fNdim](const double *x, const double *p) -> double { + return (*func)(x, static_cast(ndim), p, static_cast(npar)); + }; + f->fFunctor = std::make_unique>(ROOT::Math::ParamFunctorTempl(wrapper)); + } else { + f->fFunctor.reset(new TF1::TF1FunctorPointerImpl(ROOT::Math::ParamFunctorTempl(func))); + } } f->fParams = std::make_unique(f->fNpar); diff --git a/hist/hist/test/test_tf1.cxx b/hist/hist/test/test_tf1.cxx index 64c25bdca5387..dc40d75590ee4 100644 --- a/hist/hist/test/test_tf1.cxx +++ b/hist/hist/test/test_tf1.cxx @@ -11,6 +11,7 @@ #include "ROOT/TestSupport.hxx" #include +#include #include class MyClass { @@ -240,6 +241,29 @@ TEST(TF1, Constructors) EXPECT_EQ(tf1(&x, &p), 2); } +TEST(TF1, LambdaWithSizes) +{ + // lambda with explicit ndim and npar -- allows safe bound checking inside + auto f4arg = [](const double *x, std::size_t ndim, const double *p, std::size_t npar) -> double { + EXPECT_EQ(ndim, std::size_t{1}); + EXPECT_EQ(npar, std::size_t{2}); + return p[0] * x[0] + p[1]; + }; + + TF1 f("f4arg", f4arg, 0, 10, 2); + f.SetParameters(3.0, 1.0); + + EXPECT_NEAR(f.Eval(2.0), 7.0, 1e-10); + EXPECT_NEAR(f.Eval(5.0), 16.0, 1e-10); + + // same but passing via pointer + TF1 fptr("f4arg_ptr", &f4arg, 0, 10, 2); + fptr.SetParameters(3.0, 1.0); + + EXPECT_NEAR(fptr.Eval(2.0), 7.0, 1e-10); + EXPECT_NEAR(fptr.Eval(5.0), 16.0, 1e-10); +} + TEST(TF1, Save) { TF1 linear("linear", "x", -10., 10.);