robotpy-build icon indicating copy to clipboard operation
robotpy-build copied to clipboard

Properly handle virtual base classes without default constructor

Open virtuald opened this issue 1 year ago • 1 comments

#pragma once

class MMBase {
public:
    explicit MMBase(int number, 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;
};

class MMChild : public virtual MMBase {
public:
    MMChild(int number, std::string name) : MMBase(number, std::move(name)) {};
};

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:

template <typename PyTrampolineBase, typename PyTrampolineCfg>
struct PyTrampoline___MMBase : PyTrampolineBase,
                               virtual py::trampoline_self_life_support {
  using PyTrampolineBase::PyTrampolineBase;
};

// lots of other nonsense elided

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.

virtuald avatar Oct 03 '22 02:10 virtuald