mirror of
https://github.com/boostorg/python.git
synced 2026-01-30 20:12:37 +00:00
Renamed ExtensionClass::register_coerce() into ExtensionClass::def_standard_coerce() and made it public.
Added ClassWrapper::def_standard_coerce(). [SVN r8272]
This commit is contained in:
@@ -92,6 +92,10 @@ class ClassWrapper
|
||||
void def_read_write(MemberType T::*pm, const char* name)
|
||||
{ m_class->def_read_write(pm, name); }
|
||||
|
||||
// define the standard coercion needed for operator overloading
|
||||
void def_standard_coerce()
|
||||
{ m_class->def_standard_coerce(); }
|
||||
|
||||
// declare the given class a base class of this one and register
|
||||
// conversion functions
|
||||
template <class S, class V>
|
||||
|
||||
14
extclass.h
14
extclass.h
@@ -480,7 +480,10 @@ class ExtensionClass
|
||||
this->def_getter(pm, name);
|
||||
this->def_setter(pm, name);
|
||||
}
|
||||
|
||||
|
||||
// define the standard coercion needed for operator overloading
|
||||
void def_standard_coerce();
|
||||
|
||||
// declare the given class a base class of this one and register
|
||||
// up and down conversion functions
|
||||
template <class S, class V>
|
||||
@@ -526,7 +529,7 @@ class ExtensionClass
|
||||
template <long which, class Operand>
|
||||
inline void def_operators(operators<which,Operand>)
|
||||
{
|
||||
register_coerce();
|
||||
def_standard_coerce();
|
||||
|
||||
// for some strange reason, this prevents MSVC from having an
|
||||
// "unrecoverable block scoping error"!
|
||||
@@ -558,7 +561,7 @@ class ExtensionClass
|
||||
template <long which, class Left, class Right>
|
||||
inline void def_operators(operators<which,Left>, right_operand<Right>)
|
||||
{
|
||||
register_coerce();
|
||||
def_standard_coerce();
|
||||
|
||||
choose_op<(which & op_add)>::template args<Left,Right>::add(this);
|
||||
choose_op<(which & op_sub)>::template args<Left,Right>::add(this);
|
||||
@@ -578,7 +581,7 @@ class ExtensionClass
|
||||
template <long which, class Left, class Right>
|
||||
inline void def_operators(operators<which,Right>, left_operand<Left>)
|
||||
{
|
||||
register_coerce();
|
||||
def_standard_coerce();
|
||||
|
||||
choose_rop<(which & op_add)>::template args<Left,Right>::add(this);
|
||||
choose_rop<(which & op_sub)>::template args<Left,Right>::add(this);
|
||||
@@ -601,7 +604,6 @@ class ExtensionClass
|
||||
this->add_constructor_object(InitFunction<Holder>::create(sig));
|
||||
}
|
||||
|
||||
void register_coerce();
|
||||
};
|
||||
|
||||
// A simple wrapper over a T which allows us to use ExtensionClass<T> with a
|
||||
@@ -736,7 +738,7 @@ ExtensionClass<T, U>::ExtensionClass(const char* name)
|
||||
}
|
||||
|
||||
template <class T, class U>
|
||||
void ExtensionClass<T, U>::register_coerce()
|
||||
void ExtensionClass<T, U>::def_standard_coerce()
|
||||
{
|
||||
Ptr coerce_fct = dict().get_item(String("__coerce__"));
|
||||
|
||||
|
||||
@@ -542,6 +542,9 @@ class ExtensionClass
|
||||
this->def_setter(pm, name);
|
||||
}
|
||||
|
||||
// define the standard coercion needed for operator overloading
|
||||
void def_standard_coerce();
|
||||
|
||||
// declare the given class a base class of this one and register
|
||||
// up and down conversion functions
|
||||
template <class S, class V>
|
||||
@@ -587,7 +590,7 @@ class ExtensionClass
|
||||
template <long which, class Operand>
|
||||
inline void def_operators(operators<which,Operand>)
|
||||
{
|
||||
register_coerce();
|
||||
def_standard_coerce();
|
||||
|
||||
detail::choose_op<(which & op_add)>::template args<Operand>::add(this);
|
||||
detail::choose_op<(which & op_sub)>::template args<Operand>::add(this);
|
||||
@@ -615,7 +618,7 @@ class ExtensionClass
|
||||
template <long which, class Left, class Right>
|
||||
inline void def_operators(operators<which,Left>, right_operand<Right>)
|
||||
{
|
||||
register_coerce();
|
||||
def_standard_coerce();
|
||||
|
||||
detail::choose_op<(which & op_add)>::template args<Left,Right>::add(this);
|
||||
detail::choose_op<(which & op_sub)>::template args<Left,Right>::add(this);
|
||||
@@ -635,7 +638,7 @@ class ExtensionClass
|
||||
template <long which, class Left, class Right>
|
||||
inline void def_operators(operators<which,Right>, left_operand<Left>)
|
||||
{
|
||||
register_coerce();
|
||||
def_standard_coerce();
|
||||
|
||||
detail::choose_rop<(which & op_add)>::template args<Left,Right>::add(this);
|
||||
detail::choose_rop<(which & op_sub)>::template args<Left,Right>::add(this);
|
||||
@@ -657,8 +660,6 @@ class ExtensionClass
|
||||
{
|
||||
this->add_constructor_object(InitFunction<Holder>::create(sig));
|
||||
}
|
||||
|
||||
void register_coerce();
|
||||
};
|
||||
|
||||
// A simple wrapper over a T which allows us to use ExtensionClass<T> with a
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
2000-11-20 10:00
|
||||
Ullrich renamed ExtensionClass:register_coerce() into
|
||||
ExtensionClass:def_standard_coerce() and made it public
|
||||
|
||||
Ullrich improved shared_pod_manager.
|
||||
|
||||
|
||||
126
special.html
126
special.html
@@ -13,18 +13,122 @@
|
||||
Overview
|
||||
</h2>
|
||||
<p>
|
||||
Py_cpp supports all of the standard <a href=
|
||||
Py_cpp is able to wrap suitable C++ functions and C++ operators into Python operators.
|
||||
It supports all of the standard <a href=
|
||||
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/specialnames.html">
|
||||
special method names</a> supported by real Python class instances <em>
|
||||
except:</em>
|
||||
<ul>
|
||||
<li>the <code>__r<em><name></em>__</code> "reversed operand" <a href=
|
||||
"http://www.pythonlabs.com/pub/www.python.org/doc/current/ref/numeric-types.html">
|
||||
numeric methods</a>, and
|
||||
<li><code>__complex__</code>
|
||||
</ul>
|
||||
|
||||
(more on the reasons <a href="#reasons">below</a>). So, for example, we can wrap a
|
||||
special method names</a> supported by real Python class instances <em>except</em>
|
||||
<code>__complex__</code> (more on the reasons <a href="#reasons">below</a>).
|
||||
|
||||
|
||||
<h2>Numeric Operators</h2>
|
||||
|
||||
There are two fundamental ways to define numeric operators within py_cpp: automatic wrapping
|
||||
and manual wrapping. Suppose, C++ defines an addition operator for type <code>Rational</code>, so that we can write:
|
||||
|
||||
<pre>
|
||||
Rational a, b, c;
|
||||
...
|
||||
c = a + b;
|
||||
</pre>
|
||||
|
||||
To enable the same functionality in Python, we first wrap the Rational class as usual:
|
||||
|
||||
<pre>
|
||||
py::ClassWrapper<Rational> rational_class(my_module, "Rational");
|
||||
rational_class.def(py::Constructor<>());
|
||||
...
|
||||
</pre>
|
||||
|
||||
Then we export the addition operator like this:
|
||||
|
||||
<pre>
|
||||
rational_class.def(py::operators<py::op_add>());
|
||||
</pre>
|
||||
|
||||
Since Rational also supports subtraction, multiplication, adn division, we want to export those also. This can be done in a single command by 'or'ing the operator identifiers together (a complete list of these identifiers and the corresponding operators can be found in the <a href="#numeric_table">table</a>):
|
||||
|
||||
<pre>
|
||||
rational_class.def(py::operators<(py::op_sub | py::op_mul | py::op_div)>());
|
||||
</pre>
|
||||
|
||||
Note that the or-expression must be enclosed in parentheses. This form of operator definition will wrap homogeneous operators, that is operators whose left and right operand have the same type. Now, suppose that our C++ library also supports addition of Rationals and integers:
|
||||
|
||||
<pre>
|
||||
Rational a, b;
|
||||
int i;
|
||||
...
|
||||
a = b + i;
|
||||
a = i + b;
|
||||
</pre>
|
||||
|
||||
To wrap these heterogeneous operators (left and right hand side have different types), we need a possibility to specify a different operand type. This is done using the <code>right_operand</code> and <code>left_operand</code> templates:
|
||||
|
||||
<pre>
|
||||
rational_class.def(py::operators<py::op_add>(), py::right_operand<int>());
|
||||
rational_class.def(py::operators<py::op_add>(), py::left_operand<int>());
|
||||
</pre>
|
||||
|
||||
Py_cpp uses overloading to register several variants of the same operation (more on this in the context of <a href="#coercion">coercion</a>). Again, several operators can be exported at once:
|
||||
|
||||
<pre>
|
||||
rational_class.def(py::operators<(py::op_sub | py::op_mul | py::op_div)>(),
|
||||
py::right_operand<int>());
|
||||
rational_class.def(py::operators<(py::op_sub | py::op_mul | py::op_div)>(),
|
||||
py::left_operand<int>());
|
||||
</pre>
|
||||
|
||||
|
||||
The type of the operand not mentioned is taken from the class object. In our example, the class object is <code>rational_class</code>, and thus the other operand's type is `<code>Rational const &</code>'. You can override this default by explicitly specifying a type in the <code>operators</code> template:
|
||||
|
||||
<pre>
|
||||
rational_class.def(py::operators<py::op_add, Rational>(), py::right_operand<int>());
|
||||
</pre>
|
||||
|
||||
Here, `<code>Rational</code>' would be used instead of `<code>Rational const &</code>'.
|
||||
<p>
|
||||
Note that automatic wrapping doesn't need any specific form of <code>operator+()</code> (or any other operator), but rather wraps the <em>expression</em> `<code>left + right</code>'. That is, this mechanism can be used for any definition of <code>operator+()</code>, such as a free function `<code>Rational operator+(Rational, Rational)</code>' or a member function `<code>Rational Rational::operator+(Rational)</code>'.
|
||||
|
||||
<p>
|
||||
In some cases, automatic wrapping of operators is not possible or not desirable. Suppose, for example, that the power operation for Rationals is defined by a set of functions <code>pow()</code>:
|
||||
|
||||
<pre>
|
||||
Rational pow(Rational const & left, Rational const & right);
|
||||
Rational pow(Rational const & left, int right);
|
||||
Rational pow(int left, Rational const & right);
|
||||
</pre>
|
||||
|
||||
In order to create the Python operator "pow" from these functions, we have to wrap them manually:
|
||||
|
||||
<pre>
|
||||
rational_class.def((Rational (*)(Rational const &, Rational const &))&pow, "__pow__");
|
||||
rational_class.def((Rational (*)(Rational const &, int))&pow, "__pow__");
|
||||
</pre>
|
||||
|
||||
The third form (with <code>int</code> as left operand) cannot be wrapped this way. We must first create a function <code>rpow()</code> with the operands reversed:
|
||||
|
||||
<pre>
|
||||
Rational rpow(Rational const & right, int left)
|
||||
{
|
||||
return pow(left, right);
|
||||
}
|
||||
</pre>
|
||||
|
||||
This function must be wrapped under the name "__rpow__":
|
||||
|
||||
<pre>
|
||||
rational_class.def(&rpow, "__rpow__");
|
||||
</pre>
|
||||
|
||||
A list of the possible operator names is also found in the <a href="#numeric_table">table</a>.
|
||||
Special treatment is necessary to define the <a href="#ternary_pow">ternary pow</a>.
|
||||
<p>
|
||||
Automatic and manual wrapping can be mixed arbitrarily.
|
||||
|
||||
<a name="coercion">
|
||||
<h4>Coercion</h4></a>
|
||||
|
||||
|
||||
So, for example, we can wrap a
|
||||
<code>std::map<std::size_t,std::string></code> as follows:
|
||||
<h2>
|
||||
Example
|
||||
|
||||
Reference in New Issue
Block a user