4

C++ プライベート コンストラクターをブースト python でラップできますか? シングルトン C++ クラスがあり、それを Python にラップしたいと考えています。

c++ のプライベート メンバー関数を boost python でラップできますか?

本当にありがとう

4

2 に答える 2

4

次のようなものを使用します。

#include <boost/python.hpp>
#include <iostream>

using namespace boost::python;
using std::cout;

class Singleton
{
    private:
        Singleton()
        {
            cout << "Creating instance\n";
        }
    friend Singleton* create(); 
};

Singleton* pInstance_;
Singleton* create()
{       
    if(!pInstance_)
    {
        pInstance_ = new Singleton();
    }
    else
    {
        cout << "Using old instance\n";         
    }       
    return pInstance_;
}

BOOST_PYTHON_MODULE(cppmodule)
{
    def("create", create, return_value_policy<reference_existing_object>());
    class_<Singleton>("Singleton", no_init);
}

/* using singleton later in code */

Singleton* otherInstance_ = create();

セッション:

>>> import cppmodule
Creating instance
>>> s = cppmodule.Singleton()
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
RuntimeError: This class cannot be instantiated from Python
>>> s = cppmodule.create()
Using old instance
于 2013-08-22T23:22:51.170 に答える
1

シングルトンは多くの場合、そのコンストラクターをプライベートな可視性で宣言し、ファクトリー関数にプライベート コンストラクターへのアクセスを提供します。

class singleton
{
public:

  /// @brief Public factory function.
  static singleton& instance()
  {
    static singleton instance_;
    return instance_;
  }

private:

  // Private constructors and destructor.
  singleton()  {}
  ~singleton() {};

  singleton(const singleton&);
  singleton& operator=(const singleton&);
};

デフォルトでは、Boost.Python は、コンストラクターに提供されたinit-expressionboost::python::class_と一致する、公開されているコンストラクターを想定しています。この動作を抑制するために、特別なオブジェクトをコンストラクターboost::python::no_initに提供できます。class_さらに、プライベート デストラクタのため、テンプレート引数としてclass_提供することにより、コピー不可として公開する必要があります。boost::noncopyable

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  python::class_<singleton, boost::noncopyable>("Singleton", python::no_init);
}

Python では、シングルトンが API を介してシングルトンとして表示されることはめったにありません。example.Singleton()そのため、多くの Python 開発者は当然のことながら、factor メソッドを使用するのではなく、 を介して Python クラスをインスタンス化できると期待するかもしれません。既定のコンストラクターは を介し​​て公開されていますがpython::no_init、カスタム コンストラクターを 用に定義できます__init__。C++ シングルトンを適切に説明するために、Boost.Python を介して公開されboost::shared_ptrたシングルトンは、シングルトンへのハンドルを保持するために無操作デリータを使用します。完全な例を次に示します。

#include <boost/python.hpp>

/// @brief Mock up singleton class.
class singleton
{
public:
  /// @brief Public factory function.
  static singleton& instance()
  {
    static singleton instance_;
    return instance_;
  }

  void set_x(unsigned int x) { x_ = x;    }
  unsigned int get_x()       { return x_; }

private:

  // Private constructors and destructor.
  singleton() : x_(0) {}
  ~singleton() {};

  singleton(const singleton&);
  singleton& operator=(const singleton&);

private:
  unsigned int x_;
};

/// @brief No operation deleter.
void noop_deleter(void*) {};

/// @brief Helper function used to get a shared_ptr that holds
///        a singleton.
boost::shared_ptr<singleton> py_get_singleton()
{
  return boost::shared_ptr<singleton>(
    &singleton::instance(), // the instance
    &noop_deleter);         // no-op deleter
}

BOOST_PYTHON_MODULE(example)
{
  namespace python = boost::python;
  // Expose the singleton class, supressing the default constructor
  // via python::no_init, and providing a constructor that will return
  // a handle to the singleton.
  python::class_<singleton, boost::shared_ptr<singleton>,
                 boost::noncopyable>("Singleton", python::no_init)
    .def("__init__", python::make_constructor(&py_get_singleton))
    .add_property("x", &singleton::get_x, &singleton::set_x)
    ;
}

そしてその使用法:

>>> import example
>>> s1 = example.Singleton()
>>> s2 = example.Singleton()
>>> s1.x
0
>>> s2.x
0
>>> s1.x = 5
>>> s2.x
5

Python の観点から見ると、これはアイデンティティではなく状態を共有するため、borg または monostate パターンに似ていることに注意してください。(すなわちs1.x == s2.x、しかしid(s1) != id(s2).) Python クラスがその状態だけでなくシングルトンでもある必要がある場合は、C++ ではなく Python コードでこの動作を実装する必要があるかもしれません。

于 2013-08-23T17:11:40.513 に答える