From b83eb58000e0974d2b485c0a51d0010651ae0e23 Mon Sep 17 00:00:00 2001
From: cmoineau <cyril.moineau@cea.fr>
Date: Thu, 29 Feb 2024 07:46:35 +0000
Subject: [PATCH] Add SET_IMPL_MACRO macro to fix copy ctor bug.

---
 include/aidge/operator/Conv.hpp   |  4 ++--
 include/aidge/utils/Registrar.hpp | 33 +++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 2 deletions(-)

diff --git a/include/aidge/operator/Conv.hpp b/include/aidge/operator/Conv.hpp
index 97e27f8d3..552aee6ba 100644
--- a/include/aidge/operator/Conv.hpp
+++ b/include/aidge/operator/Conv.hpp
@@ -23,7 +23,7 @@
 #include "aidge/operator/OperatorTensor.hpp"
 #include "aidge/operator/Producer.hpp"
 #include "aidge/utils/StaticAttributes.hpp"
-#include "aidge/utils/Registrar.hpp"
+#include "aidge/utils/Registrar.hpp" // SET_IMPL_MACRO
 #include "aidge/utils/Types.h"
 
 namespace Aidge {
@@ -174,7 +174,7 @@ std::vector<std::pair<std::vector<Aidge::DimSize_t>, std::vector<DimSize_t>>> co
     }
 
     void setBackend(const std::string &name, DeviceIdx_t device = 0) override {
-        mImpl = Registrar<Conv_Op<DIM>>::create(name)(*this);
+        SET_IMPL_MACRO(Conv_Op<DIM>, *this, name);
         mOutputs[0]->setBackend(name, device);
 
         // By default, automatically set backend for weight and bias inputs
diff --git a/include/aidge/utils/Registrar.hpp b/include/aidge/utils/Registrar.hpp
index 65ba636a5..b2a98113f 100644
--- a/include/aidge/utils/Registrar.hpp
+++ b/include/aidge/utils/Registrar.hpp
@@ -30,6 +30,9 @@ namespace Aidge {
 namespace py = pybind11;
 #endif
 
+// Abstract class used to test if a class is Registrable.
+class AbstractRegistrable {};
+
 template <class DerivedClass, class Key, class Func> // curiously rucurring template pattern
 class Registrable {
 public:
@@ -110,6 +113,36 @@ void declare_registrable(py::module& m, const std::string& class_name){
 }
 #endif
 
+/*
+* This macro allow to set an implementation to an operator
+* This macro is mandatory for using implementation registered in python
+* PyBind when calling create method will do a call to the copy ctor if
+* op is not visible to the python world (if the create method return a python function)
+* See this issue for more information https://github.com/pybind/pybind11/issues/4417
+* Note: using a method to do this is not possible has any call to a function will call
+* the cpy ctor. This is why I used a macro
+* Note: I duplicated
+*             (op).setImpl(Registrar<T_Op>::create(backend_name)(op)); \
+* This is because the py::cast need to be done in the same scope.
+* I know this only empyrically not sure what happens under the hood...
+*
+* If someone wants to find an alternative to this Macro, you can contact me:
+*   cyril.moineau@cea.fr
+*/
+#ifdef PYBIND
+#define SET_IMPL_MACRO(T_Op, op, backend_name) \
+     \
+        if(Py_IsInitialized()) { \
+            auto obj = py::cast(&(op)); \
+            (op).setImpl(Registrar<T_Op>::create(backend_name)(op)); \
+        } else { \
+            (op).setImpl(Registrar<T_Op>::create(backend_name)(op)); \
+        }
+#else
+#define SET_IMPL_MACRO(T_Op, op, backend_name) \
+    (op).setImpl(Registrar<T_Op>::create(backend_name)(op));
+#endif
+
 }
 
 #endif //AIDGE_CORE_UTILS_REGISTRAR_H_
-- 
GitLab