0

A class template consists of pure virtual function and inherited by another class. I am not getting the right path to bind it. Following Error Message has appeared while trying to compile.
I have gone through the following link to find the solution 1, 2, 3, 4 but don't understand what to do. I am pasted my code here.

folder structure

proj
  -include/sample_code.h
  -lib/pybind11
  -scripts/cpp_py_cmake.py (also here pybind module stores)
  -src/
    -binding.cpp
  -CMakeLists.txt

sample_code.h

#include <iostream>
using namespace std;

/**
 * class template with virtual function */

template<typename T = int>
class Base_Abstract
{
protected:
    T base_Variable;

public:
    Base_Abstract(T x):base_Variable{x}{
        std::cout<<"Base_Abstract Class Constructor is called and Mem Var: "<<base_Variable<<std::endl;
    }
    virtual void do_something_abstract(T val) = 0;

    virtual ~Base_Abstract() {}
};

template<typename T = int>
class Derived_Abstract : public Base_Abstract<T>
{
    public:
        Derived_Abstract(T a, T b):Base_Abstract<T>{b}, derived_Variable{a}{
            std::cout<<"Derived_Abstract Class Constructor is called and a: "<<a<<" ,derived_var: "<<derived_Variable<<" , val for base: "<<b<<std::endl;
        }
        void show_derived_value(){ 
            cout<<"show_derived_value() of  Derived_Abstract class derived_Variable: "<<derived_Variable<<endl;
        };
        void do_something_abstract(T g) override{
            cout<<"virtual function is called from Derived_Abstract class when g: "<<g<<endl;
        };

        virtual ~Derived_Abstract(){}

    private:
        T derived_Variable;

};

pybind related code binding.cpp

#include <pybind11/pybind11.h>
#include "sample_code.h"
namespace py = pybind11;

/**
 * class template which is abstract class and inherited
 */

template <typename T = int>
void declare_class_template_abstarct(py::module &m, const std::string& typestr1)
{
    class PyVirtualClass : public Base_Abstract <T>{
        public:
            using Base_1 = Base_Abstract<T>;

            /* Trampoline (need one for each virtual function) */
            void do_something_abstract(int val) override {
                PYBIND11_OVERRIDE_PURE(
                    void, /* Return type */
                    Base_1,      /* Parent class */
                    do_something_abstract,          /* Name of function in C++ (must match Python name) */
                    val      /* Argument(s) */
                    );
            }

    };

    py::class_<Base_Abstract <T>, PyVirtualClass /* <--- trampoline*/>(m,"Base_Abstract")
        .def(py::init<T>())
        .def("do_something_abstract", &Base_Abstract <T>::do_something_abstract);

    py::class_<Derived_Abstract<T>, Base_Abstract<T>>(m, "Derived_Abstract")
        .def(py::init<T,T>())
        .def("show_derived_value", &Derived_Abstract <T>::show_derived_value)
        .def("do_something_abstract", &Derived_Abstract <T>::do_something_abstract);
};

PYBIND11_MODULE(somecode, m) 
{
    declare_class_template_abstarct<int>(m, "int");
}

/*
<%
setup_pybind11(cfg)
%>
*/

CMakeLists.txt file used to compile the code

cmake_minimum_required(VERSION 3.10)
project(somecode)

set(LIB_GEN_PATH ${PROJECT_SOURCE_DIR}/scripts CACHE STRING "Where generated library will be placed")

add_subdirectory(lib/pybind11)

include_directories(${PROJECT_SOURCE_DIR}/include)

pybind11_add_module(${PROJECT_NAME} 
                    ${PROJECT_SOURCE_DIR}/src/binding.cpp)

set_target_properties(${PROJECT_NAME}
    PROPERTIES
    LIBRARY_OUTPUT_DIRECTORY ${LIB_GEN_PATH}
)

cpp_py_cmake.py

import somecode

class_temp_abstract_class_obj = somecode.Derived_Abstract(42, 59)

Any suggestion is highly appreciable.

user10634362
  • 549
  • 5
  • 21
  • Please be more specific than "will not work". – molbdnilo Feb 16 '21 at 16:05
  • @molbdnilo done. actually it is not compiled and I am sure that it will be as I have not added **required pybind way of dealing with virtual function**. but the problem is I am not getting the right way to add it. – user10634362 Feb 16 '21 at 16:28
  • Do you really believe "it will show an error" is much better? What exactly is the error, and what is "it"? – molbdnilo Feb 16 '21 at 16:34
  • I don't understand how could I more explain the issue. In summary, I want to wrap a ```template class with virtual function``` in ```pybind```. I am succeeded with the template part but while I have added the virtual function then an error occurs. That's why I have written that **I am pretty sure error will come** as I have not added any functionality in ```pybind``` side for virtual function. so my request here is that I need a working example based on my case. – user10634362 Feb 17 '21 at 09:25
  • None of this has anything to do with pybind, or with Python in general. The problem is that you can't create instances of an "abstract" class (one that has pure virtual functions). – molbdnilo Feb 17 '21 at 09:37
  • I am not trying to create instances of ```abstract class```. I will just bind it using ```pybind``` and then from python side I will create ```child class``` to inherit this ```abstract class``` – user10634362 Feb 17 '21 at 13:29
  • Yes, you are (or at least pybind is). As described in the documentation and example you linked, you need to define a "trampoline" class that has overrides for the pure virtual functions. – molbdnilo Feb 17 '21 at 14:10
  • Yes that ```trampoline class``` related solution I am actually searching. I am not understanding the structure/ where and how to write it. This is my query. – user10634362 Feb 17 '21 at 14:12
  • @molbdnilo can you please take a look now? I have tried but to create the ```trampoline``` but still cannot compile. Updated the question with code. – user10634362 Feb 17 '21 at 16:32
  • @molbdnilo now you can see. I have used a derived class here too. Same code is working in CPP(the header file and cpp. No pybind11) – user10634362 Feb 18 '21 at 10:20

1 Answers1

0

Got the solution. It is about the trampoline of pybind.
using Base_Abstract_Only<T>::Base_Abstract_Only; it will be solved.
A working gist is given here.
binding.cpp

#include <pybind11/pybind11.h>

namespace py = pybind11;


template <typename T = int>
void declare_class_template_abstarct(py::module &m, const std::string& typestr1)
{
    // using Base_2 = Base_Abstract<T>;
    class PyVirtualClass : public Base_Abstract<T>{
        public:
            using Base_Abstract<T>::Base_Abstract;
            // using Base_1 = Base_Abstract<T>;

            /* Trampoline (need one for each virtual function) */
            void do_something_abstract(T val) override {
                PYBIND11_OVERRIDE_PURE(
                    void, /* Return type */
                    Base_Abstract<T>,      /* Parent class */
                    do_something_abstract,          /* Name of function in C++ (must match Python name) */
                    val      /* Argument(s) */
                    );
            }

    };

    py::class_<Base_Abstract <T>, PyVirtualClass /* <--- trampoline*/>(m,"Base_Abstract")
        .def(py::init<T>())
        .def("do_something_abstract", &Base_Abstract <T>::do_something_abstract);

    py::class_<Derived_Abstract<T>, Base_Abstract<T>>(m, "Derived_Abstract")
        .def(py::init<T,T>())
        .def("show_derived_value", &Derived_Abstract <T>::show_derived_value)
        .def("do_something_abstract", &Derived_Abstract <T>::do_something_abstract);
};

PYBIND11_MODULE(somecode, m) 
{
    declare_class_template_abstarct<int>(m, "int");
}

user10634362
  • 549
  • 5
  • 21