[C++-sig] Adding method at run-time to class instances

Christophe Tornieri christophe.tornieri at cm-labs.com
Fri Dec 21 23:16:04 CET 2012


Here is some code. The main idea is that I don't want to expose each
derived module classes but only the interface IModule that contains all the
necessary information at run-time.

The following code is actually working but produces the following warning:

to-Python converter for class ModuleConfiguration already registered;
second conversion method ignored

This sounds normal as the class is exposed each time a new instance of
MyModule or MySecondModule is created.

// Dummy class for test
class IModule
     : public Vx::VxInputOutputInterface
{
public:
    IModule() {}
};

class ModuleConfiguration
{
public:
    ModuleConfiguration(IModule& iProxy);

    IModule& mProxy;
};

template<typename T> struct GetParameterFunctor;

template<>
struct GetParameterFunctor<int>
{
    GetParameterFunctor(const std::string& iName)
        : mName(iName)
    {

    }

    int operator()(ModuleConfiguration* iProxy)
    {
        return
iProxy->mProxy.getParameter(mName).getFieldBase().toInteger();
    }

    std::string mName;
};

template<typename T>
struct SetParameterFunctor
{
    SetParameterFunctor(const std::string& iName)
        : mName(iName)
    {

    }

    int operator()(ModuleConfiguration* iProxy, T iValue)
    {
        return iProxy->mProxy.getParameter(mName).setValue(iValue);
    }

    std::string mName;
};

namespace boostVx {
    namespace python
    {
        namespace detail
        {
            boostVx::mpl::vector<int, ModuleConfiguration*>
get_signature(boostVx::function<int (ModuleConfiguration*)>,
ModuleConfiguration*)
            {
                return boostVx::mpl::vector<int, ModuleConfiguration*>();
            }

            boostVx::mpl::vector<int, ModuleConfiguration*, int>
get_signature(boostVx::function<int (ModuleConfiguration*, int)>,
ModuleConfiguration*)
            {
                return boostVx::mpl::vector<int, ModuleConfiguration*,
int>();
            }
        }
    }
}

class CreateGetParameterFieldVisitor
    : public VxData::FieldVisitor
{
public:

CreateGetParameterFieldVisitor(boostVx::python::class_<ModuleConfiguration>&
iPythonConfigurationWrapper)
        : mPythonConfigurationWrapper(iPythonConfigurationWrapper)
    {}

    virtual void visit(VxData::Field<int>& i_field)
    {
        GetParameterFunctor<int> getP(i_field.getID().asString());
        SetParameterFunctor<int> setP(i_field.getID().asString());


mPythonConfigurationWrapper.add_property(i_field.getID().asString(),
boostVx::function<int (ModuleConfiguration*)>(getP), boostVx::function<int
(ModuleConfiguration*, int)>(setP));
    }

private:
    boostVx::python::class_<ModuleConfiguration>&
mPythonConfigurationWrapper;
};

ModuleConfiguration::ModuleConfiguration(IModule& iProxy)
    : mProxy(iProxy)
{
    boostVx::python::class_<ModuleConfiguration>
pythonConfigurationWrapper("ModuleConfiguration", boostVx::python::no_init);

    CreateGetParameterFieldVisitor visitor(pythonConfigurationWrapper);


const_cast<VxData::Container&>(mProxy.getParameterContainer()).accept(visitor);
}

class ModuleWrapperInterface
{
public:
    ModuleWrapperInterface(IModule* iProxy)
        : mProxy(iProxy)
        , mConfiguration(*iProxy)
    {
    }

    ModuleConfiguration& getModuleConfiguration() { return mConfiguration; }

private:
    IModule* mProxy;

    ModuleConfiguration mConfiguration;
};

class MyModule
    : public IModule
{
public:
    MyModule()
        : mThreshold(5, "threshold", this)
        , mCeil(10, "ceil", this)
    {
    }

    const char* getClassName() const { return "MyModule"; }

private:
    Vx::VxParameter<int> mThreshold;

    Vx::VxParameter<int> mCeil;
};

class MySecondModule
    : public IModule
{
public:
    MySecondModule()
        : mTorque(120, "torque", this)
    {
    }

    const char* getClassName() const { return "MySecondModule"; }

private:
    Vx::VxParameter<int> mTorque;
};

boostVx::shared_ptr<ModuleWrapperInterface> createModule(const std::string&
iName)
{
    if( iName == "first" )
        return boostVx::shared_ptr<ModuleWrapperInterface>(new
ModuleWrapperInterface(new MyModule()), NullDeleter());
    else if( iName == "second" )
        return boostVx::shared_ptr<ModuleWrapperInterface>(new
ModuleWrapperInterface(new MySecondModule()), NullDeleter());
    else
    {
        std::cerr << "No module with name " << iName << " found, returning
MyModule." << std::endl;
        return boostVx::shared_ptr<ModuleWrapperInterface>(new
ModuleWrapperInterface(new MyModule()), NullDeleter());
    }
}

BOOST_PYTHON_MODULE(Modules)
{
    boostVx::python::class_<ModuleWrapperInterface,
boostVx::shared_ptr<ModuleWrapperInterface>,
boostVx::noncopyable>("ModuleInterface", boostVx::python::no_init)
            .def("getParameters",
&ModuleWrapperInterface::getModuleConfiguration,
boostVx::python::return_internal_reference<>() );

    boostVx::python::def("createModule", &createModule);
}



-- 
Christophe Tornieri
Tech Lead, Software Architect Sub-sea division
christophe.tornieri at cm-labs.com

http://www.vxsim.com/
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/cplusplus-sig/attachments/20121221/2e2aeafb/attachment.html>


More information about the Cplusplus-sig mailing list