Open virtuald opened 1 year ago
Here's a full cpp file that contains all the trampoline elements and fails to compile:
#include <string>
// bug where a virtual base with an explicit constructor wouldn't compile
class MMBase {
public:
explicit MMBase(std::string name) : m_name(std::move(name)) {}
virtual ~MMBase() = default;
MMBase(const MMBase &) = delete;
MMBase &operator=(const MMBase &) = delete;
std::string getName() const { return m_name; }
private:
std::string m_name;
};
namespace rpygen {
struct EmptyTrampolineCfg {};
}; // namespace rpygen
namespace py {
struct trampoline_self_life_support {
trampoline_self_life_support() = default;
};
}; // namespace py
namespace rpygen {
template <typename CfgBase = EmptyTrampolineCfg>
struct PyTrampolineCfg___MMBase : CfgBase {
using Base = ::MMBase;
};
template <typename PyTrampolineBase, typename PyTrampolineCfg>
struct PyTrampoline___MMBase : PyTrampolineBase,
virtual py::trampoline_self_life_support {
using PyTrampolineBase::PyTrampolineBase;
};
}; // namespace rpygen
class MMChild : public virtual MMBase {
public:
MMChild(int number, std::string name) : MMBase(std::move(name)){};
};
namespace rpygen {
template <typename CfgBase>
using PyTrampolineCfgBase___MMChild = PyTrampolineCfg___MMBase<CfgBase>;
template <typename CfgBase = EmptyTrampolineCfg>
struct PyTrampolineCfg___MMChild : PyTrampolineCfgBase___MMChild<CfgBase> {
using Base = ::MMChild;
};
template <typename PyTrampolineBase, typename PyTrampolineCfg>
using PyTrampolineBase___MMChild =
PyTrampoline___MMBase<PyTrampolineBase, PyTrampolineCfg>;
template <typename PyTrampolineBase, typename PyTrampolineCfg>
struct PyTrampoline___MMChild
: PyTrampolineBase___MMChild<PyTrampolineBase, PyTrampolineCfg> {
using PyTrampolineBase___MMChild<PyTrampolineBase,
PyTrampolineCfg>::PyTrampolineBase___MMChild;
// also insert here
};
}; // namespace rpygen
using MMChild_Trampoline = rpygen::PyTrampoline___MMChild<
typename ::MMChild, typename rpygen::PyTrampolineCfg___MMChild<>>;
MMChild_Trampoline x(1, "h");
The only way I can currently bind this is by disabling trampolines, which disallows inheriting from these types using python. The reason is because the way I currently deal with this is like so:
The PyTrampolineBase template parameter can be the child class -- and the advantage of this is that our using declaration just brings in whatever constructors are defined in the child, and this works for grandchildren and subsequent descendants too -- while still providing proper bindings for each class being inherited.
Unfortunately, you can't do this with a virtual base class that doesn't have a default constructor, as it's undefined.
I experimented with a few things trying to understand this, and concluded that I don't really want to fix this right now -- I can just disable the trampolines for the specified type and it compiles. The core problem is that each level of inheritance that we use to compose the trampoline needs to have a constructor specific to the current class that we're defining a trampoline for. The current system assumes that the intermediate classes don't need to know anything about those inheriting from them, so this just isn't really possible.
One way this could be achievable is we could put all of the contents of the trampolines in separate include files, and compose them all that way instead... though, I think that might break in certain inheritance cases? There's a lot of bad solutions to this problem.