Search code examples
c++boostbindingboost-python

Private constructor with Boost.Python


I am trying to bind a C++ class with a private constructor using Boost.Python.

Let assume that I have the following class:

class Test
{
    public:
        static Test& GetInstance()
        {
            static Test globalInstance;
            return globalInstance;
        }

        int content(){return 0;}

    private:
        Test(){std::cout << "Object constructed" << std::endl;}
};

This class has a private constructor and to get an instance of the class, we must call the GetInstance() method.

I tried to bind it, using the following code:

BOOST_PYTHON_MODULE(test)
{
    class_<Test>("Test", no_init)
        .def("create", &Test::GetInstance)
        .def("content", &Test::content);
}

This code does not compile and gives me two errors:

  • /Sources/Boost/boost/python/detail/invoke.hpp:75:12: error: type 'const boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<Test &>' does not provide a call operator
  • /Sources/Boost/boost/python/detail/caller.hpp:102:98: error: no member named 'get_pytype' in 'boost::python::detail::specify_a_return_value_policy_to_wrap_functions_returning<Test &>'

However, if I create a function, which calls GetInstance(), like the following:

Test create()
{
    return Test::GetInstance();
}

and that I replace .def("create", &Test::GetInstance) by .def("create", create) in my binding, everything works fine.

Why can't I use the public GetInstance() method directly?


Solution

  • The problem here actually comes from the lack of explicit return policy. If a function/method does not return by value, we must set its return policy to one of:

    • reference_existing_object
    • copy_non_const_reference
    • copy_const_reference
    • manage_new_object
    • return_by_value

    So, simply binding the GetInstance() method like so:

    .def("create", &Test::GetInstance, return_value_policy<copy_non_const_reference>())
    

    solves the issue.

    Hope it can help someone, as the error messages from Boost don't help that much here…