From 52a7437808e44f7a4f70a9ad3663d7322e0b342d Mon Sep 17 00:00:00 2001 From: Vipul Cariappa Date: Wed, 23 Jul 2025 16:49:00 +0200 Subject: [PATCH] [cppyy] fix: instantiation of templated functions when instantiating with another templated function --- .../cppyy/CPyCppyy/src/TemplateProxy.cxx | 6 ++++ .../pyroot/cppyy/cppyy/test/test_templates.py | 36 +++++++++++++++++++ .../cling/lib/Interpreter/LookupHelper.cpp | 4 ++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/bindings/pyroot/cppyy/CPyCppyy/src/TemplateProxy.cxx b/bindings/pyroot/cppyy/CPyCppyy/src/TemplateProxy.cxx index 20ea4929adfc5..e3ffbc3655901 100644 --- a/bindings/pyroot/cppyy/CPyCppyy/src/TemplateProxy.cxx +++ b/bindings/pyroot/cppyy/CPyCppyy/src/TemplateProxy.cxx @@ -142,6 +142,12 @@ PyObject* TemplateProxy::Instantiate(const std::string& fname, } else PyErr_Clear(); + if (!bArgSet && (Py_TYPE(itemi) == &TemplateProxy_Type)) { + TemplateProxy *tp = (TemplateProxy*)itemi; + PyObject *tmpl_name = CPyCppyy_PyText_FromFormat("decltype(%s%s)", tp->fTI->fCppName.c_str(), tp->fTemplateArgs ? CPyCppyy_PyText_AsString(tp->fTemplateArgs) : ""); + PyTuple_SET_ITEM(tpArgs, i, tmpl_name); + bArgSet = true; + } if (!bArgSet) { // normal case (may well fail) PyErr_Clear(); diff --git a/bindings/pyroot/cppyy/cppyy/test/test_templates.py b/bindings/pyroot/cppyy/cppyy/test/test_templates.py index 9f41b8e968a14..429705e914594 100644 --- a/bindings/pyroot/cppyy/cppyy/test/test_templates.py +++ b/bindings/pyroot/cppyy/cppyy/test/test_templates.py @@ -1341,5 +1341,41 @@ def test01_reduce_binary(self): assert type(e1+e2) == cppyy.gbl.TypeReduction.Expr[int] +class TestTEMPLATED_CALLBACK: + def setup_class(cls): + cls.test_dct = test_dct + import cppyy + cls.templates = cppyy.load_reflection_info(cls.test_dct) + + def test01_templated_callbacks(self): + import cppyy + from cppyy.gbl import std + + cppyy.cppdef(r""" + bool foo() { return true; } + + int bar(int a, int b) { return a + b; } + + template + T baz(T a, U b, std::string c) { + return (T)(a + b) + std::stoi(c); + } + + template + R returned_callback(F callable, R r, Args... args) { + return callable(r, std::forward(args)...); + } + + template + bool callback(F callable, Args&&... args) { + return callable(std::forward(args)...); + } + """) + + assert cppyy.gbl.callback(cppyy.gbl.foo) + assert cppyy.gbl.returned_callback(cppyy.gbl.bar, 1, 1) == 2 + assert cppyy.gbl.returned_callback(cppyy.gbl.baz[int, int], 1, 1, std.string("1")) == 3 + + if __name__ == "__main__": exit(pytest.main(args=['-sv', '-ra', __file__])) diff --git a/interpreter/cling/lib/Interpreter/LookupHelper.cpp b/interpreter/cling/lib/Interpreter/LookupHelper.cpp index 5761c0bcd325c..2efe43daed333 100644 --- a/interpreter/cling/lib/Interpreter/LookupHelper.cpp +++ b/interpreter/cling/lib/Interpreter/LookupHelper.cpp @@ -1691,7 +1691,9 @@ namespace cling { clang::QualType QT = clang::Sema::GetTypeFromParser(Res.get(), &TSI); QT = QT.getCanonicalType(); { - ExprValueKind VK = VK_PRValue; + // XValue is an object that can be "moved" whereas PRValue is temporary value + // This enables overloads that require the object to be moved + ExprValueKind VK = VK_XValue; if (QT->getAs()) { VK = VK_LValue; }