boost/python/operators.hpp

はじめに

<boost/python/operators.hpp> は、Python の特殊メソッドを C++ の対応する構造から自動的に生成する型と関数を提供する。これらの構造の大半は演算子式であり、ヘッダの名前はそこから来ている。この機能を使用するには、エクスポートする式中でラップするクラス型のオブジェクトを self オブジェクトで置き換え、その結果を class_<>::def へ渡す。このヘッダがエクスポートするものの大半は実装部分と考えるべきであり、本稿では詳細について記述しない。

クラス

self_ns::self_t クラス

class self_ns::self_t

self_ns::self_tself オブジェクトの実際の型である。ライブラリは self_t を自身の名前空間 self_ns 内に分離し、他の文脈で引数依存の探索により一般化された演算子テンプレートが発見されるのを防ぐ。ユーザが直接 self_t に触れることはないため、これは実装の詳細と考えるべきである。

self_ns::self_t クラスの概要

namespace boost { namespace python { namespace self_ns {
{
   unspecified-type-declaration self_t;

   // 複合演算子
   template <class T> operator_<unspecified> operator+=(self_t, T);
   template <class T> operator_<unspecified> operator-=(self_t, T);
   template <class T> operator_<unspecified> operator*=(self_t, T);
   template <class T> operator_<unspecified> operator/=(self_t, T);
   template <class T> operator_<unspecified> operator%=(self_t, T);
   template <class T> operator_<unspecified> operator>>=(self_t, T);
   template <class T> operator_<unspecified> operator<<=(self_t, T);
   template <class T> operator_<unspecified> operator&=(self_t, T);
   template <class T> operator_<unspecified> operator^=(self_t, T);
   template <class T> operator_<unspecified> operator|=(self_t, T);

   // 比較演算子
   template <class L, class R> operator_<unspecified> operator==(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator!=(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator<(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator>(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator<=(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator>=(L const&, R const&);

   // 非メンバ演算子
   template <class L, class R> operator_<unspecified> operator+(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator-(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator*(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator/(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator%(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator>>(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator<<(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator&(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator^(L const&, R const&);
   template <class L, class R> operator_<unspecified> operator|(L const&, R const&);
   template <class L, class R> operator_<unspecified> pow(L const&, R const&);

   // 単項演算子
   operator_<unspecified> operator-(self_t);
   operator_<unspecified> operator+(self_t);
   operator_<unspecified> operator~(self_t);
   operator_<unspecified> operator!(self_t);

   // 値操作
   operator_<unspecified> int_(self_t);
   operator_<unspecified> long_(self_t);
   operator_<unspecified> float_(self_t);
   operator_<unspecified> complex_(self_t);
   operator_<unspecified> str(self_t);

   operator_<unspecified> repr(self_t);

}}};

各式の結果を class_<>::def の引数として渡したときに生成されるメソッドを以下の表に挙げる。x はラップするクラス型のオブジェクトである。

self_ns::self_t クラスの複合演算子

下表において rother 型のオブジェクトの場合、y は型 T のオブジェクトである。それ以外の場合、yr と同じ型のオブジェクトである。

C++ の式

Python のメソッド名

C++ の実装

self += r

__iadd__

x += y

self -= r

__isub__

x -= y

self *= r

__imul__

x *= y

self /= r

__idiv__

x /= y

self %= r

__imod__

x %= y

self >>= r

__irshift__

x >>= y

self <<= r

__ilshift__

x <<= y

self &= r

__iand__

x &= y

self ^= r

__ixor__

x ^= y

self |= r

__ior__

x |= y

self_ns::self_t クラスの比較関数

下表において rself_t 型の場合、yx と同じ型のオブジェクトである。lrother<T> 型のオブジェクトの場合、y は型 T のオブジェクトである。それ以外の場合、ylr と同じ型のオブジェクトであり、lself_t 型以外である。

「Python の式」の列は、x および y の型へ変換可能なオブジェクトについて Python がサポートする式を表す。2 番目の演算は Python の高水準比較演算子の反射則(可換則)により生じるもので、対応する演算が y オブジェクトのメソッドとして定義されない場合のみ使用される。

C++ の式

Python のメソッド名

C++ の実装

Python の式(1 番目、2 番目)

self == r

__eq__

x == y

x == y, y == x

l == self

__eq__

y == x

y == x, x == y

self != r

__ne__

x != y

x != y, y != x

l != self

__ne__

y != x

y != x, x != y

self < r

__lt__

x < y

x < y, y > x

l < self

__gt__

y < x

y > x, x < y

self > r

__gt__

x > y

x > y, y < x

l > self

__lt__

y > x

y < x, x > y

self <= r

__le__

x <= y

x <= y, y >= x

l <= self

__ge__

y <= x

y >= x, x <= y

self >= r

__ge__

x >= y

x >= y, y <= x

l >= self

__le__

y >= x

y <= x, x >= y

self_ns::self_t クラスの非メンバ演算子

ここで述べられているように、以下の名前が「__r」で始まる演算は左オペランドが与えられた演算をサポートしない場合のみ呼び出される。

C++ の式

Python のメソッド名

C++ の実装

self + r

__add__

x + y

l + self

__radd__

y + x

self - r

__sub__

x - y

l - self

__rsub__

y - x

self * r

__mul__

x * y

l * self

__rmul__

y * x

self / r

__div__

x / y

l / self

__rdiv__

y / x

self % r

__mod__

x % y

l % self

__rmod__

y % x

self >> r

__rshift__

x >> y

l >> self

__rrshift__

y >> x

self << r

__lshift__

x << y

l << self

__rlshift__

y << x

self & r

__and__

x & y

l & self

__rand__

y & x

self ^ r

__xor__

x ^ y

l ^ self

__rxor__

y ^ x

self | r

__or__

x | y

l | self

__ror__

y | x

pow(self, r)

__pow__

pow(x, y)

pow(l, self)

__rpow__

pow(y, x)

self_ns::self_t クラスの単項演算子

C++ の式

Python のメソッド名

C++ の実装

-self

__neg__

-x

+self

__pos__

+x

~self

__invert__

~x

not self または !self

__nonzero__

!!x

self_ns::self_t クラスの値演算

C++ の式

Python のメソッド

C++ の実装1

int_(self)

__int__

long(x)

long_

__long__

PyLong_FromLong(x)

float_

__float__

double(x)

complex_

__complex__

std::complex<double>(x)

str

__str__

lexical_cast<std::string>(x)

repr

__repr__

lexical_cast<std::string>(x)

other クラステンプレート

template<class T>
struct other

other<T> のインスタンスは self とともに演算子式中で使用し、結果は同じ式の other<T>T オブジェクトで置き換えたものと等価である。T オブジェクトの構築が高価で避けたい場合、コンストラクタが利用できない場合、または単純にコードを明確にする場合に other<T> を使用するとよい。

other クラステンプレートの概要

namespace boost { namespace python
template <class T>
struct other
{
};
}

detail::operator_ クラステンプレート

template<unspecified>
struct detail::operator_

detail::operator_<> のインスタンス化は、self を含む演算子式の戻り値型として使用する。これは実装の詳細として考えるべきであり、self 式の結果がどのように class_<>::def 呼び出しとマッチするか見るためとしてのみ、ここに記載する。

detail::operator_ クラステンプレートの概要

namespace boost { namespace python { namespace detail
{
  template <unspecified>
  struct operator_
  {
  };
}}}

オブジェクト

self

self_ns::self_t self = self_ns::self
namespace boost { namespace python
{
  using self_ns::self;
}}

2

#include <boost/python/module.hpp>
#include <boost/python/class.hpp>
#include <boost/python/operators.hpp>
#include <boost/operators.hpp>

struct number
   : boost::integer_arithmetic<number>
{
    explicit number(long x_) : x(x_) {}
    operator long() const { return x; }

    template <class T>
    number& operator+=(T const& rhs)
    { x += rhs; return *this; }

    template <class T>
    number& operator-=(T const& rhs)
    { x -= rhs; return *this; }

    template <class T>
    number& operator*=(T const& rhs)
    { x *= rhs; return *this; }

    template <class T>
    number& operator/=(T const& rhs)
    { x /= rhs; return *this; }

    template <class T>
    number& operator%=(T const& rhs)
    { x %= rhs; return *this; }

    long x;
};

using namespace boost::python;
BOOST_PYTHON_MODULE(demo)
{
   class_<number>("number", init<long>())
      // self との組み合わせ
      .def(self += self)
      .def(self + self)
      .def(self -= self)
      .def(self - self)
      .def(self *= self)
      .def(self * self)
      .def(self /= self)
      .def(self / self)
      .def(self %= self)
      .def(self % self)

      // Python の int への変換
      .def(int_(self))

      // long との組み合わせ
      .def(self += long())
      .def(self + long())
      .def(long() + self)
      .def(self -= long())
      .def(self - long())
      .def(long() - self)
      .def(self *= long())
      .def(self * long())
      .def(long() * self)
      .def(self /= long())
      .def(self / long())
      .def(long() / self)
      .def(self %= long())
      .def(self % long())
      .def(long() % self)
      ;
}
1

boost::lexical_cast

2

boost::integer_arithmetic