Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
P
pybind11
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
open
pybind11
Commits
8e5dceb6
Commit
8e5dceb6
authored
Sep 11, 2016
by
Wenzel Jakob
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Multiple inheritance support
parent
bad589a4
Hide whitespace changes
Inline
Side-by-side
Showing
15 changed files
with
421 additions
and
94 deletions
+421
-94
README.md
+3
-1
docs/advanced.rst
+44
-0
docs/intro.rst
+4
-2
docs/limitations.rst
+4
-7
include/pybind11/attr.h
+36
-10
include/pybind11/cast.h
+127
-33
include/pybind11/common.h
+1
-0
include/pybind11/operators.h
+0
-1
include/pybind11/pybind11.h
+49
-35
include/pybind11/pytypes.h
+1
-1
include/pybind11/stl_bind.h
+0
-2
tests/CMakeLists.txt
+1
-1
tests/test_inheritance.cpp
+1
-1
tests/test_multiple_inheritance.cpp
+85
-0
tests/test_multiple_inheritance.py
+65
-0
No files found.
README.md
View file @
8e5dceb6
...
@@ -45,10 +45,12 @@ pybind11 can map the following core C++ features to Python
...
@@ -45,10 +45,12 @@ pybind11 can map the following core C++ features to Python
-
Arbitrary exception types
-
Arbitrary exception types
-
Enumerations
-
Enumerations
-
Callbacks
-
Callbacks
-
Iterators and ranges
-
Custom operators
-
Custom operators
-
Single and multiple inheritance
-
STL data structures
-
STL data structures
-
Iterators and ranges
-
Iterators and ranges
-
Smart pointers with reference counting like
`
std::shared_ptr
`
-
Smart pointers with reference counting like
`
`std::shared_ptr`
`
-
Internal references with correct reference counting
-
Internal references with correct reference counting
-
C++ classes with virtual (and pure virtual) methods can be extended in Python
-
C++ classes with virtual (and pure virtual) methods can be extended in Python
...
...
docs/advanced.rst
View file @
8e5dceb6
...
@@ -217,6 +217,8 @@ The following interactive session shows how to call them from Python.
...
@@ -217,6 +217,8 @@ The following interactive session shows how to call them from Python.
that demonstrates how to work with callbacks and anonymous functions in
that demonstrates how to work with callbacks and anonymous functions in
more detail.
more detail.
.. _overriding_virtuals:
Overriding virtual functions in Python
Overriding virtual functions in Python
======================================
======================================
...
@@ -2151,3 +2153,45 @@ type is explicitly allowed.
...
@@ -2151,3 +2153,45 @@ type is explicitly allowed.
};
};
}
}
};
};
Multiple Inheritance
====================
pybind11 can create bindings for types that derive from multiple base types
(aka. *multiple inheritance*). To do so, specify all bases in the template
arguments of the ``class_`` declaration:
.. code-block:: cpp
py::class_<MyType, BaseType1, BaseType2, BaseType3>(m, "MyType")
...
The base types can be specified in arbitrary order, and they can even be
interspersed with alias types and holder types (discussed earlier in this
document)---pybind11 will automatically find out which is which. The only
requirement is that the first template argument is the type to be declared.
There are two caveats regarding the implementation of this feature:
1. When only one base type is specified for a C++ type that actually has
multiple bases, pybind11 will assume that it does not participate in
multiple inheritance, which can lead to undefined behavior. In such cases,
add the tag ``multiple_inheritance``:
.. code-block:: cpp
py::class_<MyType, BaseType2>(m, "MyType", py::multiple_inheritance());
The tag is redundant and does not need to be specified when multiple base
types are listed.
2. As was previously discussed in the section on :ref:`overriding_virtuals`, it
is easy to create Python types that derive from C++ classes. It is even
possible to make use of multiple inheritance to declare a Python class which
has e.g. a C++ and a Python class as bases. However, any attempt to create a
type that has *two or more* C++ classes in its hierarchy of base types will
fail with a fatal error message: ``TypeError: multiple bases have instance
lay-out conflict``. Core Python types that are implemented in C (e.g.
``dict``, ``list``, ``Exception``, etc.) also fall under this combination
and cannot be combined with C++ types bound using pybind11 via multiple
inheritance.
docs/intro.rst
View file @
8e5dceb6
...
@@ -35,12 +35,14 @@ The following core C++ features can be mapped to Python
...
@@ -35,12 +35,14 @@ The following core C++ features can be mapped to Python
- Instance methods and static methods
- Instance methods and static methods
- Overloaded functions
- Overloaded functions
- Instance attributes and static attributes
- Instance attributes and static attributes
-
Exception
s
-
Arbitrary exception type
s
- Enumerations
- Enumerations
- Iterators and ranges
- Callbacks
- Callbacks
- Iterators and ranges
- Custom operators
- Custom operators
- Single and multiple inheritance
- STL data structures
- STL data structures
- Iterators and ranges
- Smart pointers with reference counting like ``std::shared_ptr``
- Smart pointers with reference counting like ``std::shared_ptr``
- Internal references with correct reference counting
- Internal references with correct reference counting
- C++ classes with virtual (and pure virtual) methods can be extended in Python
- C++ classes with virtual (and pure virtual) methods can be extended in Python
...
...
docs/limitations.rst
View file @
8e5dceb6
...
@@ -9,15 +9,12 @@ certain limitations:
...
@@ -9,15 +9,12 @@ certain limitations:
values. This means that some additional care is needed to avoid bugs that
values. This means that some additional care is needed to avoid bugs that
would be caught by the type checker in a traditional C++ program.
would be caught by the type checker in a traditional C++ program.
- Multiple inheritance relationships on the C++ side cannot be mapped to
Python.
- The NumPy interface ``pybind11::array`` greatly simplifies accessing
- The NumPy interface ``pybind11::array`` greatly simplifies accessing
numerical data from C++ (and vice versa), but it's not a full-blown array
numerical data from C++ (and vice versa), but it's not a full-blown array
class like ``Eigen::Array`` or ``boost.multi_array``.
class like ``Eigen::Array`` or ``boost.multi_array``.
All of these features could be implemented but would lead to a significant
These features could be implemented but would lead to a significant increase in
increase in complexity. I've decided to draw the line here to keep this project
complexity. I've decided to draw the line here to keep this project simple and
simple and compact. Users who absolutely require these features are encouraged
compact. Users who absolutely require these features are encouraged to fork
to fork
pybind11.
pybind11.
include/pybind11/attr.h
View file @
8e5dceb6
...
@@ -41,6 +41,9 @@ template <typename T> struct base {
...
@@ -41,6 +41,9 @@ template <typename T> struct base {
/// Keep patient alive while nurse lives
/// Keep patient alive while nurse lives
template
<
int
Nurse
,
int
Patient
>
struct
keep_alive
{
};
template
<
int
Nurse
,
int
Patient
>
struct
keep_alive
{
};
/// Annotation indicating that a class is involved in a multiple inheritance relationship
struct
multiple_inheritance
{
};
NAMESPACE_BEGIN
(
detail
)
NAMESPACE_BEGIN
(
detail
)
/* Forward declarations */
/* Forward declarations */
enum
op_id
:
int
;
enum
op_id
:
int
;
...
@@ -127,6 +130,8 @@ struct function_record {
...
@@ -127,6 +130,8 @@ struct function_record {
/// Special data structure which (temporarily) holds metadata about a bound class
/// Special data structure which (temporarily) holds metadata about a bound class
struct
type_record
{
struct
type_record
{
PYBIND11_NOINLINE
type_record
()
{
}
/// Handle to the parent scope
/// Handle to the parent scope
handle
scope
;
handle
scope
;
...
@@ -148,21 +153,36 @@ struct type_record {
...
@@ -148,21 +153,36 @@ struct type_record {
/// Function pointer to class_<..>::dealloc
/// Function pointer to class_<..>::dealloc
void
(
*
dealloc
)(
PyObject
*
)
=
nullptr
;
void
(
*
dealloc
)(
PyObject
*
)
=
nullptr
;
// Pointer to RTTI type_info data structure of base class
/// List of base classes of the newly created type
const
std
::
type_info
*
base_type
=
nullptr
;
list
bases
;
/// OR: Python handle to base class
handle
base_handle
;
/// Optional docstring
/// Optional docstring
const
char
*
doc
=
nullptr
;
const
char
*
doc
=
nullptr
;
/// Multiple inheritance marker
bool
multiple_inheritance
=
false
;
PYBIND11_NOINLINE
void
add_base
(
const
std
::
type_info
*
base
,
void
*
(
*
caster
)(
void
*
))
{
auto
base_info
=
detail
::
get_type_info
(
*
base
,
false
);
if
(
!
base_info
)
{
std
::
string
tname
(
base
->
name
());
detail
::
clean_type_id
(
tname
);
pybind11_fail
(
"generic_type: type
\"
"
+
std
::
string
(
name
)
+
"
\"
referenced unknown base type
\"
"
+
tname
+
"
\"
"
);
}
bases
.
append
((
PyObject
*
)
base_info
->
type
);
if
(
caster
)
base_info
->
implicit_casts
.
push_back
(
std
::
make_pair
(
type
,
caster
));
}
};
};
/**
/**
* Partial template specializations to process custom attributes provided to
* Partial template specializations to process custom attributes provided to
* cpp_function_ and class_. These are either used to initialize the respective
* cpp_function_ and class_. These are either used to initialize the respective
* fields in the type_record and function_record data structures or executed
* fields in the type_record and function_record data structures or executed
at
*
at
runtime to deal with custom call policies (e.g. keep_alive).
* runtime to deal with custom call policies (e.g. keep_alive).
*/
*/
template
<
typename
T
,
typename
SFINAE
=
void
>
struct
process_attribute
;
template
<
typename
T
,
typename
SFINAE
=
void
>
struct
process_attribute
;
...
@@ -257,13 +277,19 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
...
@@ -257,13 +277,19 @@ template <> struct process_attribute<arg_v> : process_attribute_default<arg_v> {
/// Process a parent class attribute
/// Process a parent class attribute
template
<
typename
T
>
template
<
typename
T
>
struct
process_attribute
<
T
,
typename
std
::
enable_if
<
std
::
is_base_of
<
handle
,
T
>::
value
>::
type
>
:
process_attribute_default
<
handle
>
{
struct
process_attribute
<
T
,
typename
std
::
enable_if
<
std
::
is_base_of
<
handle
,
T
>::
value
>::
type
>
:
process_attribute_default
<
handle
>
{
static
void
init
(
const
handle
&
h
,
type_record
*
r
)
{
r
->
base
_handle
=
h
;
}
static
void
init
(
const
handle
&
h
,
type_record
*
r
)
{
r
->
base
s
.
append
(
h
)
;
}
};
};
/// Process a parent class attribute
/// Process a parent class attribute
(deprecated, does not support multiple inheritance)
template
<
typename
T
>
template
<
typename
T
>
struct
process_attribute
<
base
<
T
>>
:
process_attribute_default
<
base
<
T
>>
{
struct
process_attribute
<
base
<
T
>>
:
process_attribute_default
<
base
<
T
>>
{
static
void
init
(
const
base
<
T
>
&
,
type_record
*
r
)
{
r
->
base_type
=
&
typeid
(
T
);
}
static
void
init
(
const
base
<
T
>
&
,
type_record
*
r
)
{
r
->
add_base
(
&
typeid
(
T
),
nullptr
);
}
};
/// Process a multiple inheritance attribute
template
<>
struct
process_attribute
<
multiple_inheritance
>
:
process_attribute_default
<
multiple_inheritance
>
{
static
void
init
(
const
multiple_inheritance
&
,
type_record
*
r
)
{
r
->
multiple_inheritance
=
true
;
}
};
};
/***
/***
...
...
include/pybind11/cast.h
View file @
8e5dceb6
...
@@ -15,7 +15,6 @@
...
@@ -15,7 +15,6 @@
#include "descr.h"
#include "descr.h"
#include <array>
#include <array>
#include <limits>
#include <limits>
#include <iostream>
NAMESPACE_BEGIN
(
pybind11
)
NAMESPACE_BEGIN
(
pybind11
)
NAMESPACE_BEGIN
(
detail
)
NAMESPACE_BEGIN
(
detail
)
...
@@ -25,9 +24,13 @@ struct type_info {
...
@@ -25,9 +24,13 @@ struct type_info {
PyTypeObject
*
type
;
PyTypeObject
*
type
;
size_t
type_size
;
size_t
type_size
;
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
);
void
(
*
init_holder
)(
PyObject
*
,
const
void
*
);
std
::
vector
<
PyObject
*
(
*
)(
PyObject
*
,
PyTypeObject
*
)
>
implicit_conversions
;
std
::
vector
<
PyObject
*
(
*
)(
PyObject
*
,
PyTypeObject
*
)
>
implicit_conversions
;
std
::
vector
<
std
::
pair
<
const
std
::
type_info
*
,
void
*
(
*
)(
void
*
)
>>
implicit_casts
;
buffer_info
*
(
*
get_buffer
)(
PyObject
*
,
void
*
)
=
nullptr
;
buffer_info
*
(
*
get_buffer
)(
PyObject
*
,
void
*
)
=
nullptr
;
void
*
get_buffer_data
=
nullptr
;
void
*
get_buffer_data
=
nullptr
;
/** A simple type never occurs as a (direct or indirect) parent
* of a class that makes use of multiple inheritance */
bool
simple_type
=
true
;
};
};
PYBIND11_NOINLINE
inline
internals
&
get_internals
()
{
PYBIND11_NOINLINE
inline
internals
&
get_internals
()
{
...
@@ -72,32 +75,34 @@ PYBIND11_NOINLINE inline internals &get_internals() {
...
@@ -72,32 +75,34 @@ PYBIND11_NOINLINE inline internals &get_internals() {
return
*
internals_ptr
;
return
*
internals_ptr
;
}
}
PYBIND11_NOINLINE
inline
detail
::
type_info
*
get_type_info
(
PyTypeObject
*
type
,
bool
throw_if_missing
=
true
)
{
PYBIND11_NOINLINE
inline
detail
::
type_info
*
get_type_info
(
PyTypeObject
*
type
)
{
auto
const
&
type_dict
=
get_internals
().
registered_types_py
;
auto
const
&
type_dict
=
get_internals
().
registered_types_py
;
do
{
do
{
auto
it
=
type_dict
.
find
(
type
);
auto
it
=
type_dict
.
find
(
type
);
if
(
it
!=
type_dict
.
end
())
if
(
it
!=
type_dict
.
end
())
return
(
detail
::
type_info
*
)
it
->
second
;
return
(
detail
::
type_info
*
)
it
->
second
;
type
=
type
->
tp_base
;
type
=
type
->
tp_base
;
if
(
!
type
)
{
if
(
!
type
)
if
(
throw_if_missing
)
pybind11_fail
(
"pybind11::detail::get_type_info: unable to find type object!"
);
return
nullptr
;
return
nullptr
;
}
}
while
(
true
);
}
while
(
true
);
}
}
PYBIND11_NOINLINE
inline
detail
::
type_info
*
get_type_info
(
const
std
::
type_info
&
tp
)
{
PYBIND11_NOINLINE
inline
detail
::
type_info
*
get_type_info
(
const
std
::
type_info
&
tp
,
bool
throw_if_missing
)
{
auto
&
types
=
get_internals
().
registered_types_cpp
;
auto
&
types
=
get_internals
().
registered_types_cpp
;
auto
it
=
types
.
find
(
std
::
type_index
(
tp
));
auto
it
=
types
.
find
(
std
::
type_index
(
tp
));
if
(
it
!=
types
.
end
())
if
(
it
!=
types
.
end
())
return
(
detail
::
type_info
*
)
it
->
second
;
return
(
detail
::
type_info
*
)
it
->
second
;
if
(
throw_if_missing
)
{
std
::
string
tname
=
tp
.
name
();
detail
::
clean_type_id
(
tname
);
pybind11_fail
(
"pybind11::detail::get_type_info: unable to find type info for
\"
"
+
tname
+
"
\"
"
);
}
return
nullptr
;
return
nullptr
;
}
}
PYBIND11_NOINLINE
inline
handle
get_type_handle
(
const
std
::
type_info
&
tp
)
{
PYBIND11_NOINLINE
inline
handle
get_type_handle
(
const
std
::
type_info
&
tp
,
bool
throw_if_missing
)
{
detail
::
type_info
*
type_info
=
get_type_info
(
tp
);
detail
::
type_info
*
type_info
=
get_type_info
(
tp
,
throw_if_missing
);
return
handle
(
type_info
?
((
PyObject
*
)
type_info
->
type
)
:
nullptr
);
return
handle
(
type_info
?
((
PyObject
*
)
type_info
->
type
)
:
nullptr
);
}
}
...
@@ -124,7 +129,7 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail:
...
@@ -124,7 +129,7 @@ PYBIND11_NOINLINE inline handle get_object_handle(const void *ptr, const detail:
auto
&
instances
=
get_internals
().
registered_instances
;
auto
&
instances
=
get_internals
().
registered_instances
;
auto
range
=
instances
.
equal_range
(
ptr
);
auto
range
=
instances
.
equal_range
(
ptr
);
for
(
auto
it
=
range
.
first
;
it
!=
range
.
second
;
++
it
)
{
for
(
auto
it
=
range
.
first
;
it
!=
range
.
second
;
++
it
)
{
auto
instance_type
=
detail
::
get_type_info
(
Py_TYPE
(
it
->
second
)
,
false
);
auto
instance_type
=
detail
::
get_type_info
(
Py_TYPE
(
it
->
second
));
if
(
instance_type
&&
instance_type
==
type
)
if
(
instance_type
&&
instance_type
==
type
)
return
handle
((
PyObject
*
)
it
->
second
);
return
handle
((
PyObject
*
)
it
->
second
);
}
}
...
@@ -149,18 +154,56 @@ inline void keep_alive_impl(handle nurse, handle patient);
...
@@ -149,18 +154,56 @@ inline void keep_alive_impl(handle nurse, handle patient);
class
type_caster_generic
{
class
type_caster_generic
{
public
:
public
:
PYBIND11_NOINLINE
type_caster_generic
(
const
std
::
type_info
&
type_info
)
PYBIND11_NOINLINE
type_caster_generic
(
const
std
::
type_info
&
type_info
)
:
typeinfo
(
get_type_info
(
type_info
))
{
}
:
typeinfo
(
get_type_info
(
type_info
,
false
))
{
}
PYBIND11_NOINLINE
bool
load
(
handle
src
,
bool
convert
)
{
PYBIND11_NOINLINE
bool
load
(
handle
src
,
bool
convert
)
{
return
load
(
src
,
convert
,
Py_TYPE
(
src
.
ptr
()));
}
bool
load
(
handle
src
,
bool
convert
,
PyTypeObject
*
tobj
)
{
if
(
!
src
||
!
typeinfo
)
if
(
!
src
||
!
typeinfo
)
return
false
;
return
false
;
if
(
src
.
is_none
())
{
if
(
src
.
is_none
())
{
value
=
nullptr
;
value
=
nullptr
;
return
true
;
return
true
;
}
else
if
(
PyType_IsSubtype
(
Py_TYPE
(
src
.
ptr
()),
typeinfo
->
type
))
{
value
=
((
instance
<
void
>
*
)
src
.
ptr
())
->
value
;
return
true
;
}
}
if
(
typeinfo
->
simple_type
)
{
/* Case 1: no multiple inheritance etc. involved */
/* Check if we can safely perform a reinterpret-style cast */
if
(
PyType_IsSubtype
(
tobj
,
typeinfo
->
type
))
{
value
=
reinterpret_cast
<
instance
<
void
>
*>
(
src
.
ptr
())
->
value
;
return
true
;
}
}
else
{
/* Case 2: multiple inheritance */
/* Check if we can safely perform a reinterpret-style cast */
if
(
tobj
==
typeinfo
->
type
)
{
value
=
reinterpret_cast
<
instance
<
void
>
*>
(
src
.
ptr
())
->
value
;
return
true
;
}
/* If this is a python class, also check the parents recursively */
auto
const
&
type_dict
=
get_internals
().
registered_types_py
;
bool
new_style_class
=
PyType_Check
(
tobj
);
if
(
type_dict
.
find
(
tobj
)
==
type_dict
.
end
()
&&
new_style_class
&&
tobj
->
tp_bases
)
{
tuple
parents
(
tobj
->
tp_bases
,
true
);
for
(
handle
parent
:
parents
)
{
bool
result
=
load
(
src
,
convert
,
(
PyTypeObject
*
)
parent
.
ptr
());
if
(
result
)
return
true
;
}
}
/* Try implicit casts */
for
(
auto
&
cast
:
typeinfo
->
implicit_casts
)
{
type_caster_generic
sub_caster
(
*
cast
.
first
);
if
(
sub_caster
.
load
(
src
,
convert
))
{
value
=
cast
.
second
(
sub_caster
.
value
);
return
true
;
}
}
}
/* Perform an implicit conversion */
if
(
convert
)
{
if
(
convert
)
{
for
(
auto
&
converter
:
typeinfo
->
implicit_conversions
)
{
for
(
auto
&
converter
:
typeinfo
->
implicit_conversions
)
{
temp
=
object
(
converter
(
src
.
ptr
(),
typeinfo
->
type
),
false
);
temp
=
object
(
converter
(
src
.
ptr
(),
typeinfo
->
type
),
false
);
...
@@ -201,7 +244,7 @@ public:
...
@@ -201,7 +244,7 @@ public:
auto
it_instances
=
internals
.
registered_instances
.
equal_range
(
src
);
auto
it_instances
=
internals
.
registered_instances
.
equal_range
(
src
);
for
(
auto
it_i
=
it_instances
.
first
;
it_i
!=
it_instances
.
second
;
++
it_i
)
{
for
(
auto
it_i
=
it_instances
.
first
;
it_i
!=
it_instances
.
second
;
++
it_i
)
{
auto
instance_type
=
detail
::
get_type_info
(
Py_TYPE
(
it_i
->
second
)
,
false
);
auto
instance_type
=
detail
::
get_type_info
(
Py_TYPE
(
it_i
->
second
));
if
(
instance_type
&&
instance_type
==
tinfo
)
if
(
instance_type
&&
instance_type
==
tinfo
)
return
handle
((
PyObject
*
)
it_i
->
second
).
inc_ref
();
return
handle
((
PyObject
*
)
it_i
->
second
).
inc_ref
();
}
}
...
@@ -262,7 +305,8 @@ template <typename type> class type_caster_base : public type_caster_generic {
...
@@ -262,7 +305,8 @@ template <typename type> class type_caster_base : public type_caster_generic {
public
:
public
:
static
PYBIND11_DESCR
name
()
{
return
type_descr
(
_
<
type
>
());
}
static
PYBIND11_DESCR
name
()
{
return
type_descr
(
_
<
type
>
());
}
type_caster_base
()
:
type_caster_generic
(
typeid
(
type
))
{
}
type_caster_base
()
:
type_caster_base
(
typeid
(
type
))
{
}
type_caster_base
(
const
std
::
type_info
&
info
)
:
type_caster_generic
(
info
)
{
}
static
handle
cast
(
const
itype
&
src
,
return_value_policy
policy
,
handle
parent
)
{
static
handle
cast
(
const
itype
&
src
,
return_value_policy
policy
,
handle
parent
)
{
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
if
(
policy
==
return_value_policy
::
automatic
||
policy
==
return_value_policy
::
automatic_reference
)
...
@@ -433,7 +477,7 @@ public:
...
@@ -433,7 +477,7 @@ public:
}
}
/* Check if this is a C++ type */
/* Check if this is a C++ type */
if
(
get_type_info
((
PyTypeObject
*
)
h
.
get_type
().
ptr
()
,
false
))
{
if
(
get_type_info
((
PyTypeObject
*
)
h
.
get_type
().
ptr
()))
{
value
=
((
instance
<
void
>
*
)
h
.
ptr
())
->
value
;
value
=
((
instance
<
void
>
*
)
h
.
ptr
())
->
value
;
return
true
;
return
true
;
}
}
...
@@ -749,22 +793,56 @@ protected:
...
@@ -749,22 +793,56 @@ protected:
/// Type caster for holder types like std::shared_ptr, etc.
/// Type caster for holder types like std::shared_ptr, etc.
template
<
typename
type
,
typename
holder_type
>
class
type_caster_holder
:
public
type_caster_base
<
type
>
{
template
<
typename
type
,
typename
holder_type
>
class
type_caster_holder
:
public
type_caster_base
<
type
>
{
public
:
public
:
using
type_caster_base
<
type
>::
cast
;
using
base
=
type_caster_base
<
type
>
;
using
type_caster_base
<
type
>::
typeinfo
;
using
base
::
base
;
using
type_caster_base
<
type
>::
value
;
using
base
::
cast
;
using
type_caster_base
<
type
>::
temp
;
using
base
::
typeinfo
;
using
base
::
value
;
using
base
::
temp
;
bool
load
(
handle
src
,
bool
convert
)
{
PYBIND11_NOINLINE
bool
load
(
handle
src
,
bool
convert
)
{
if
(
!
src
||
!
typeinfo
)
{
return
load
(
src
,
convert
,
Py_TYPE
(
src
.
ptr
()));
}
bool
load
(
handle
src
,
bool
convert
,
PyTypeObject
*
tobj
)
{
if
(
!
src
||
!
typeinfo
)
return
false
;
return
false
;
}
else
if
(
src
.
is_none
())
{
if
(
src
.
is_none
())
{
value
=
nullptr
;
value
=
nullptr
;
return
true
;
return
true
;
}
else
if
(
PyType_IsSubtype
(
Py_TYPE
(
src
.
ptr
()),
typeinfo
->
type
))
{
}
auto
inst
=
(
instance
<
type
,
holder_type
>
*
)
src
.
ptr
();
value
=
(
void
*
)
inst
->
value
;
if
(
typeinfo
->
simple_type
)
{
/* Case 1: no multiple inheritance etc. involved */
holder
=
inst
->
holder
;
/* Check if we can safely perform a reinterpret-style cast */
return
true
;
if
(
PyType_IsSubtype
(
tobj
,
typeinfo
->
type
))
{
auto
inst
=
(
instance
<
type
,
holder_type
>
*
)
src
.
ptr
();
value
=
(
void
*
)
inst
->
value
;
holder
=
inst
->
holder
;
return
true
;
}
}
else
{
/* Case 2: multiple inheritance */
/* Check if we can safely perform a reinterpret-style cast */
if
(
tobj
==
typeinfo
->
type
)
{
auto
inst
=
(
instance
<
type
,
holder_type
>
*
)
src
.
ptr
();
value
=
(
void
*
)
inst
->
value
;
holder
=
inst
->
holder
;
return
true
;
}
/* If this is a python class, also check the parents recursively */
auto
const
&
type_dict
=
get_internals
().
registered_types_py
;
bool
new_style_class
=
PyType_Check
(
tobj
);
if
(
type_dict
.
find
(
tobj
)
==
type_dict
.
end
()
&&
new_style_class
&&
tobj
->
tp_bases
)
{
tuple
parents
(
tobj
->
tp_bases
,
true
);
for
(
handle
parent
:
parents
)
{
bool
result
=
load
(
src
,
convert
,
(
PyTypeObject
*
)
parent
.
ptr
());
if
(
result
)
return
true
;
}
}
if
(
try_implicit_casts
(
src
,
convert
))
return
true
;
}
}
if
(
convert
)
{
if
(
convert
)
{
...
@@ -774,6 +852,23 @@ public:
...
@@ -774,6 +852,23 @@ public:
return
true
;
return
true
;
}
}
}
}
return
false
;
}
template
<
typename
T
=
holder_type
,
detail
::
enable_if_t
<!
std
::
is_constructible
<
T
,
const
T
&
,
type
*>::
value
,
int
>
=
0
>
bool
try_implicit_casts
(
handle
,
bool
)
{
return
false
;
}
template
<
typename
T
=
holder_type
,
detail
::
enable_if_t
<
std
::
is_constructible
<
T
,
const
T
&
,
type
*>::
value
,
int
>
=
0
>
bool
try_implicit_casts
(
handle
src
,
bool
convert
)
{
for
(
auto
&
cast
:
typeinfo
->
implicit_casts
)
{
type_caster_holder
sub_caster
(
*
cast
.
first
);
if
(
sub_caster
.
load
(
src
,
convert
))
{
value
=
cast
.
second
(
sub_caster
.
value
);
holder
=
holder_type
(
sub_caster
.
holder
,
(
type
*
)
value
);
return
true
;
}
}
return
false
;
return
false
;
}
}
...
@@ -968,7 +1063,6 @@ template <> inline void cast_safe<void>(object &&) {}
...
@@ -968,7 +1063,6 @@ template <> inline void cast_safe<void>(object &&) {}
NAMESPACE_END
(
detail
)
NAMESPACE_END
(
detail
)
template
<
return_value_policy
policy
=
return_value_policy
::
automatic_reference
,
template
<
return_value_policy
policy
=
return_value_policy
::
automatic_reference
,
typename
...
Args
>
tuple
make_tuple
(
Args
&&
...
args_
)
{
typename
...
Args
>
tuple
make_tuple
(
Args
&&
...
args_
)
{
const
size_t
size
=
sizeof
...(
Args
);
const
size_t
size
=
sizeof
...(
Args
);
...
@@ -1023,7 +1117,7 @@ struct arg_v : arg {
...
@@ -1023,7 +1117,7 @@ struct arg_v : arg {
template
<
typename
T
>
template
<
typename
T
>
arg_v
arg
::
operator
=
(
T
&&
value
)
const
{
return
{
name
,
std
::
forward
<
T
>
(
value
)};
}
arg_v
arg
::
operator
=
(
T
&&
value
)
const
{
return
{
name
,
std
::
forward
<
T
>
(
value
)};
}
/// Alias for backward compatibility -- to be remove in version 2.0
/// Alias for backward compatibility -- to be remove
d
in version 2.0
template
<
typename
/*unused*/
>
using
arg_t
=
arg_v
;
template
<
typename
/*unused*/
>
using
arg_t
=
arg_v
;
inline
namespace
literals
{
inline
namespace
literals
{
...
@@ -1199,7 +1293,7 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
...
@@ -1199,7 +1293,7 @@ unpacking_collector<policy> collect_arguments(Args &&...args) {
"Invalid function call: positional args must precede keywords and ** unpacking; "
"Invalid function call: positional args must precede keywords and ** unpacking; "
"* unpacking must precede ** unpacking"
"* unpacking must precede ** unpacking"
);
);
return
{
std
::
forward
<
Args
>
(
args
)...
};
return
{
std
::
forward
<
Args
>
(
args
)...
};
}
}
NAMESPACE_END
(
detail
)
NAMESPACE_END
(
detail
)
...
...
include/pybind11/common.h
View file @
8e5dceb6
...
@@ -89,6 +89,7 @@
...
@@ -89,6 +89,7 @@
#include <unordered_map>
#include <unordered_map>
#include <memory>
#include <memory>
#include <typeindex>
#include <typeindex>
#include <type_traits>
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
#if PY_MAJOR_VERSION >= 3 /// Compatibility macros for various Python versions
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
#define PYBIND11_INSTANCE_METHOD_NEW(ptr, class_) PyInstanceMethod_New(ptr)
...
...
include/pybind11/operators.h
View file @
8e5dceb6
...
@@ -10,7 +10,6 @@
...
@@ -10,7 +10,6 @@
#pragma once
#pragma once
#include "pybind11.h"
#include "pybind11.h"
#include <type_traits>
#if defined(__clang__) && !defined(__INTEL_COMPILER)
#if defined(__clang__) && !defined(__INTEL_COMPILER)
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
# pragma clang diagnostic ignored "-Wunsequenced" // multiple unsequenced modifications to 'self' (when using def(py::self OP Type()))
...
...
include/pybind11/pybind11.h
View file @
8e5dceb6
...
@@ -17,6 +17,7 @@
...
@@ -17,6 +17,7 @@
# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
# pragma warning(disable: 4512) // warning C4512: Assignment operator was implicitly defined as deleted
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
# pragma warning(disable: 4800) // warning C4800: 'int': forcing value to bool 'true' or 'false' (performance warning)
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
# pragma warning(disable: 4996) // warning C4996: The POSIX name for this item is deprecated. Instead, use the ISO C and C++ conformant name
# pragma warning(disable: 4702) // warning C4702: unreachable code
#elif defined(__INTEL_COMPILER)
#elif defined(__INTEL_COMPILER)
# pragma warning(push)
# pragma warning(push)
# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero
# pragma warning(disable: 186) // pointless comparison of unsigned integer with zero
...
@@ -576,18 +577,6 @@ public:
...
@@ -576,18 +577,6 @@ public:
PYBIND11_OBJECT_DEFAULT
(
generic_type
,
object
,
PyType_Check
)
PYBIND11_OBJECT_DEFAULT
(
generic_type
,
object
,
PyType_Check
)
protected
:
protected
:
void
initialize
(
type_record
*
rec
)
{
void
initialize
(
type_record
*
rec
)
{
if
(
rec
->
base_type
)
{
if
(
rec
->
base_handle
)
pybind11_fail
(
"generic_type: specified base type multiple times!"
);
rec
->
base_handle
=
detail
::
get_type_handle
(
*
(
rec
->
base_type
));
if
(
!
rec
->
base_handle
)
{
std
::
string
tname
(
rec
->
base_type
->
name
());
detail
::
clean_type_id
(
tname
);
pybind11_fail
(
"generic_type: type
\"
"
+
std
::
string
(
rec
->
name
)
+
"
\"
referenced unknown base type
\"
"
+
tname
+
"
\"
"
);
}
}
auto
&
internals
=
get_internals
();
auto
&
internals
=
get_internals
();
auto
tindex
=
std
::
type_index
(
*
(
rec
->
type
));
auto
tindex
=
std
::
type_index
(
*
(
rec
->
type
));
...
@@ -617,6 +606,12 @@ protected:
...
@@ -617,6 +606,12 @@ protected:
ht_qualname
=
name
;
ht_qualname
=
name
;
}
}
#endif
#endif
size_t
num_bases
=
rec
->
bases
.
size
();
tuple
bases
(
num_bases
);
for
(
size_t
i
=
0
;
i
<
num_bases
;
++
i
)
bases
[
i
]
=
rec
->
bases
[
i
];
std
::
string
full_name
=
(
scope_module
?
((
std
::
string
)
scope_module
.
str
()
+
"."
+
rec
->
name
)
std
::
string
full_name
=
(
scope_module
?
((
std
::
string
)
scope_module
.
str
()
+
"."
+
rec
->
name
)
:
std
::
string
(
rec
->
name
));
:
std
::
string
(
rec
->
name
));
...
@@ -629,6 +624,11 @@ protected:
...
@@ -629,6 +624,11 @@ protected:
memcpy
((
void
*
)
tp_doc
,
rec
->
doc
,
size
);
memcpy
((
void
*
)
tp_doc
,
rec
->
doc
,
size
);
}
}
/* Danger zone: from now (and until PyType_Ready), make sure to
issue no Python C API calls which could potentially invoke the
garbage collector (the GC will call type_traverse(), which will in
turn find the newly constructed type in an invalid state) */
object
type_holder
(
PyType_Type
.
tp_alloc
(
&
PyType_Type
,
0
),
false
);
object
type_holder
(
PyType_Type
.
tp_alloc
(
&
PyType_Type
,
0
),
false
);
auto
type
=
(
PyHeapTypeObject
*
)
type_holder
.
ptr
();
auto
type
=
(
PyHeapTypeObject
*
)
type_holder
.
ptr
();
...
@@ -646,8 +646,12 @@ protected:
...
@@ -646,8 +646,12 @@ protected:
/* Basic type attributes */
/* Basic type attributes */
type
->
ht_type
.
tp_name
=
strdup
(
full_name
.
c_str
());
type
->
ht_type
.
tp_name
=
strdup
(
full_name
.
c_str
());
type
->
ht_type
.
tp_basicsize
=
(
ssize_t
)
rec
->
instance_size
;
type
->
ht_type
.
tp_basicsize
=
(
ssize_t
)
rec
->
instance_size
;
type
->
ht_type
.
tp_base
=
(
PyTypeObject
*
)
rec
->
base_handle
.
ptr
();
rec
->
base_handle
.
inc_ref
();
if
(
num_bases
>
0
)
{
type
->
ht_type
.
tp_base
=
(
PyTypeObject
*
)
((
object
)
bases
[
0
]).
inc_ref
().
ptr
();
type
->
ht_type
.
tp_bases
=
bases
.
release
().
ptr
();
rec
->
multiple_inheritance
|=
num_bases
>
1
;
}
type
->
ht_name
=
name
.
release
().
ptr
();
type
->
ht_name
=
name
.
release
().
ptr
();
...
@@ -689,9 +693,23 @@ protected:
...
@@ -689,9 +693,23 @@ protected:
if
(
rec
->
scope
)
if
(
rec
->
scope
)
rec
->
scope
.
attr
(
handle
(
type
->
ht_name
))
=
*
this
;
rec
->
scope
.
attr
(
handle
(
type
->
ht_name
))
=
*
this
;
if
(
rec
->
multiple_inheritance
)
mark_parents_nonsimple
(
&
type
->
ht_type
);
type_holder
.
release
();
type_holder
.
release
();
}
}
/// Helper function which tags all parents of a type using mult. inheritance
void
mark_parents_nonsimple
(
PyTypeObject
*
value
)
{
tuple
t
(
value
->
tp_bases
,
true
);
for
(
handle
h
:
t
)
{
auto
tinfo2
=
get_type_info
((
PyTypeObject
*
)
h
.
ptr
());
if
(
tinfo2
)
tinfo2
->
simple_type
=
false
;
mark_parents_nonsimple
((
PyTypeObject
*
)
h
.
ptr
());
}
}
/// Allocate a metaclass on demand (for static properties)
/// Allocate a metaclass on demand (for static properties)
handle
metaclass
()
{
handle
metaclass
()
{
auto
&
ht_type
=
((
PyHeapTypeObject
*
)
m_ptr
)
->
ht_type
;
auto
&
ht_type
=
((
PyHeapTypeObject
*
)
m_ptr
)
->
ht_type
;
...
@@ -811,31 +829,18 @@ protected:
...
@@ -811,31 +829,18 @@ protected:
static
void
releasebuffer
(
PyObject
*
,
Py_buffer
*
view
)
{
delete
(
buffer_info
*
)
view
->
internal
;
}
static
void
releasebuffer
(
PyObject
*
,
Py_buffer
*
view
)
{
delete
(
buffer_info
*
)
view
->
internal
;
}
};
};
template
<
template
<
typename
>
class
Predicate
,
typename
...
BaseTypes
>
struct
class_selector
;
template
<
template
<
typename
>
class
Predicate
,
typename
Base
,
typename
...
Bases
>
struct
class_selector
<
Predicate
,
Base
,
Bases
...
>
{
static
inline
void
set_bases
(
detail
::
type_record
&
record
)
{
if
(
Predicate
<
Base
>::
value
)
record
.
base_type
=
&
typeid
(
Base
);
else
class_selector
<
Predicate
,
Bases
...
>::
set_bases
(
record
);
}
};
template
<
template
<
typename
>
class
Predicate
>
struct
class_selector
<
Predicate
>
{
static
inline
void
set_bases
(
detail
::
type_record
&
)
{}
};
NAMESPACE_END
(
detail
)
NAMESPACE_END
(
detail
)
template
<
typename
type_
,
typename
...
options
>
template
<
typename
type_
,
typename
...
options
>
class
class_
:
public
detail
::
generic_type
{
class
class_
:
public
detail
::
generic_type
{
template
<
typename
T
>
using
is_holder
=
detail
::
is_holder_type
<
type_
,
T
>
;
template
<
typename
T
>
using
is_holder
=
detail
::
is_holder_type
<
type_
,
T
>
;
template
<
typename
T
>
using
is_subtype
=
detail
::
bool_constant
<
std
::
is_base_of
<
type_
,
T
>::
value
&&
!
std
::
is_same
<
T
,
type_
>::
value
>
;
template
<
typename
T
>
using
is_subtype
=
detail
::
bool_constant
<
std
::
is_base_of
<
type_
,
T
>::
value
&&
!
std
::
is_same
<
T
,
type_
>::
value
>
;
template
<
typename
T
>
using
is_base
_class
=
detail
::
bool_constant
<
std
::
is_base_of
<
T
,
type_
>::
value
&&
!
std
::
is_same
<
T
,
type_
>::
value
>
;
template
<
typename
T
>
using
is_base
=
detail
::
bool_constant
<
std
::
is_base_of
<
T
,
type_
>::
value
&&
!
std
::
is_same
<
T
,
type_
>::
value
>
;
template
<
typename
T
>
using
is_valid_class_option
=
template
<
typename
T
>
using
is_valid_class_option
=
detail
::
bool_constant
<
detail
::
bool_constant
<
is_holder
<
T
>::
value
||
is_holder
<
T
>::
value
||
is_subtype
<
T
>::
value
||
is_subtype
<
T
>::
value
||
is_base
_class
<
T
>::
value
is_base
<
T
>::
value
>
;
>
;
public
:
public
:
...
@@ -848,9 +853,6 @@ public:
...
@@ -848,9 +853,6 @@ public:
static_assert
(
detail
::
all_of_t
<
is_valid_class_option
,
options
...
>::
value
,
static_assert
(
detail
::
all_of_t
<
is_valid_class_option
,
options
...
>::
value
,
"Unknown/invalid class_ template parameters provided"
);
"Unknown/invalid class_ template parameters provided"
);
static_assert
(
detail
::
count_t
<
is_base_class
,
options
...
>::
value
<=
1
,
"Invalid class_ base types: multiple inheritance is not supported"
);
PYBIND11_OBJECT
(
class_
,
detail
::
generic_type
,
PyType_Check
)
PYBIND11_OBJECT
(
class_
,
detail
::
generic_type
,
PyType_Check
)
template
<
typename
...
Extra
>
template
<
typename
...
Extra
>
...
@@ -864,7 +866,9 @@ public:
...
@@ -864,7 +866,9 @@ public:
record
.
init_holder
=
init_holder
;
record
.
init_holder
=
init_holder
;
record
.
dealloc
=
dealloc
;
record
.
dealloc
=
dealloc
;
detail
::
class_selector
<
is_base_class
,
options
...
>::
set_bases
(
record
);
/* Register base classes specified via template arguments to class_, if any */
bool
unused
[]
=
{
(
add_base
<
options
>
(
record
),
false
)...
};
(
void
)
unused
;
/* Process optional arguments, if any */
/* Process optional arguments, if any */
detail
::
process_attributes
<
Extra
...
>::
init
(
extra
...,
&
record
);
detail
::
process_attributes
<
Extra
...
>::
init
(
extra
...,
&
record
);
...
@@ -877,6 +881,16 @@ public:
...
@@ -877,6 +881,16 @@ public:
}
}
}
}
template
<
typename
Base
,
std
::
enable_if_t
<
is_base
<
Base
>::
value
,
int
>
=
0
>
static
void
add_base
(
detail
::
type_record
&
rec
)
{
rec
.
add_base
(
&
typeid
(
Base
),
[](
void
*
src
)
->
void
*
{
return
static_cast
<
Base
*>
(
reinterpret_cast
<
type
*>
(
src
));
});
}
template
<
typename
Base
,
std
::
enable_if_t
<!
is_base
<
Base
>::
value
,
int
>
=
0
>
static
void
add_base
(
detail
::
type_record
&
)
{
}
template
<
typename
Func
,
typename
...
Extra
>
template
<
typename
Func
,
typename
...
Extra
>
class_
&
def
(
const
char
*
name_
,
Func
&&
f
,
const
Extra
&
...
extra
)
{
class_
&
def
(
const
char
*
name_
,
Func
&&
f
,
const
Extra
&
...
extra
)
{
cpp_function
cf
(
std
::
forward
<
Func
>
(
f
),
name
(
name_
),
cpp_function
cf
(
std
::
forward
<
Func
>
(
f
),
name
(
name_
),
...
@@ -1198,7 +1212,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
...
@@ -1198,7 +1212,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
iterator
make_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
iterator
make_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
typedef
detail
::
iterator_state
<
Iterator
,
Sentinel
,
false
,
Policy
>
state
;
typedef
detail
::
iterator_state
<
Iterator
,
Sentinel
,
false
,
Policy
>
state
;
if
(
!
detail
::
get_type_info
(
typeid
(
state
)))
{
if
(
!
detail
::
get_type_info
(
typeid
(
state
)
,
false
))
{
class_
<
state
>
(
handle
(),
"iterator"
)
class_
<
state
>
(
handle
(),
"iterator"
)
.
def
(
"__iter__"
,
[](
state
&
s
)
->
state
&
{
return
s
;
})
.
def
(
"__iter__"
,
[](
state
&
s
)
->
state
&
{
return
s
;
})
.
def
(
"__next__"
,
[](
state
&
s
)
->
ValueType
{
.
def
(
"__next__"
,
[](
state
&
s
)
->
ValueType
{
...
@@ -1223,7 +1237,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
...
@@ -1223,7 +1237,7 @@ template <return_value_policy Policy = return_value_policy::reference_internal,
iterator
make_key_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
iterator
make_key_iterator
(
Iterator
first
,
Sentinel
last
,
Extra
&&
...
extra
)
{
typedef
detail
::
iterator_state
<
Iterator
,
Sentinel
,
true
,
Policy
>
state
;
typedef
detail
::
iterator_state
<
Iterator
,
Sentinel
,
true
,
Policy
>
state
;
if
(
!
detail
::
get_type_info
(
typeid
(
state
)))
{
if
(
!
detail
::
get_type_info
(
typeid
(
state
)
,
false
))
{
class_
<
state
>
(
handle
(),
"iterator"
)
class_
<
state
>
(
handle
(),
"iterator"
)
.
def
(
"__iter__"
,
[](
state
&
s
)
->
state
&
{
return
s
;
})
.
def
(
"__iter__"
,
[](
state
&
s
)
->
state
&
{
return
s
;
})
.
def
(
"__next__"
,
[](
state
&
s
)
->
KeyType
{
.
def
(
"__next__"
,
[](
state
&
s
)
->
KeyType
{
...
...
include/pybind11/pytypes.h
View file @
8e5dceb6
...
@@ -612,7 +612,7 @@ public:
...
@@ -612,7 +612,7 @@ public:
}
}
size_t
size
()
const
{
return
(
size_t
)
PyList_Size
(
m_ptr
);
}
size_t
size
()
const
{
return
(
size_t
)
PyList_Size
(
m_ptr
);
}
detail
::
list_accessor
operator
[](
size_t
index
)
const
{
return
detail
::
list_accessor
(
*
this
,
index
);
}
detail
::
list_accessor
operator
[](
size_t
index
)
const
{
return
detail
::
list_accessor
(
*
this
,
index
);
}
void
append
(
const
object
&
object
)
const
{
PyList_Append
(
m_ptr
,
object
.
ptr
());
}
void
append
(
handle
h
)
const
{
PyList_Append
(
m_ptr
,
h
.
ptr
());
}
};
};
class
args
:
public
tuple
{
PYBIND11_OBJECT_DEFAULT
(
args
,
tuple
,
PyTuple_Check
)
};
class
args
:
public
tuple
{
PYBIND11_OBJECT_DEFAULT
(
args
,
tuple
,
PyTuple_Check
)
};
...
...
include/pybind11/stl_bind.h
View file @
8e5dceb6
...
@@ -12,8 +12,6 @@
...
@@ -12,8 +12,6 @@
#include "common.h"
#include "common.h"
#include "operators.h"
#include "operators.h"
#include <type_traits>
#include <utility>
#include <algorithm>
#include <algorithm>
#include <sstream>
#include <sstream>
...
...
tests/CMakeLists.txt
View file @
8e5dceb6
...
@@ -27,9 +27,9 @@ set(PYBIND11_TEST_FILES
...
@@ -27,9 +27,9 @@ set(PYBIND11_TEST_FILES
test_pickling.cpp
test_pickling.cpp
test_python_types.cpp
test_python_types.cpp
test_sequences_and_iterators.cpp
test_sequences_and_iterators.cpp
test_smart_ptr.cpp
test_stl_binders.cpp
test_stl_binders.cpp
test_virtual_functions.cpp
test_virtual_functions.cpp
test_multiple_inheritance.cpp
)
)
string
(
REPLACE
".cpp"
".py"
PYBIND11_PYTEST_FILES
"
${
PYBIND11_TEST_FILES
}
"
)
string
(
REPLACE
".cpp"
".py"
PYBIND11_PYTEST_FILES
"
${
PYBIND11_TEST_FILES
}
"
)
...
...
tests/test_inheritance.cpp
View file @
8e5dceb6
...
@@ -61,7 +61,7 @@ test_initializer inheritance([](py::module &m) {
...
@@ -61,7 +61,7 @@ test_initializer inheritance([](py::module &m) {
.
def
(
py
::
init
<
std
::
string
>
());
.
def
(
py
::
init
<
std
::
string
>
());
/* Another way of declaring a subclass relationship: reference parent's C++ type */
/* Another way of declaring a subclass relationship: reference parent's C++ type */
py
::
class_
<
Rabbit
>
(
m
,
"Rabbit"
,
py
::
base
<
Pet
>
()
)
py
::
class_
<
Rabbit
,
Pet
>
(
m
,
"Rabbit"
)
.
def
(
py
::
init
<
std
::
string
>
());
.
def
(
py
::
init
<
std
::
string
>
());
/* And another: list parent in class template arguments */
/* And another: list parent in class template arguments */
...
...
tests/test_multiple_inheritance.cpp
0 → 100644
View file @
8e5dceb6
/*
tests/test_multiple_inheritance.cpp -- multiple inheritance,
implicit MI casts
Copyright (c) 2016 Wenzel Jakob <wenzel.jakob@epfl.ch>
All rights reserved. Use of this source code is governed by a
BSD-style license that can be found in the LICENSE file.
*/
#include "pybind11_tests.h"
PYBIND11_DECLARE_HOLDER_TYPE
(
T
,
std
::
shared_ptr
<
T
>
);
struct
Base1
{
Base1
(
int
i
)
:
i
(
i
)
{
}
int
foo
()
{
return
i
;
}
int
i
;
};
struct
Base2
{
Base2
(
int
i
)
:
i
(
i
)
{
}
int
bar
()
{
return
i
;
}
int
i
;
};
struct
Base12
:
Base1
,
Base2
{
Base12
(
int
i
,
int
j
)
:
Base1
(
i
),
Base2
(
j
)
{
}
};
struct
MIType
:
Base12
{
MIType
(
int
i
,
int
j
)
:
Base12
(
i
,
j
)
{
}
};
test_initializer
multiple_inheritance
([](
py
::
module
&
m
)
{
py
::
class_
<
Base1
>
(
m
,
"Base1"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
"foo"
,
&
Base1
::
foo
);
py
::
class_
<
Base2
>
(
m
,
"Base2"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
"bar"
,
&
Base2
::
bar
);
py
::
class_
<
Base12
,
Base1
,
Base2
>
(
m
,
"Base12"
);
py
::
class_
<
MIType
,
Base12
>
(
m
,
"MIType"
)
.
def
(
py
::
init
<
int
,
int
>
());
});
/* Test the case where not all base classes are specified,
and where pybind11 requires the py::multiple_inheritance
flag to perform proper casting between types */
struct
Base1a
{
Base1a
(
int
i
)
:
i
(
i
)
{
}
int
foo
()
{
return
i
;
}
int
i
;
};
struct
Base2a
{
Base2a
(
int
i
)
:
i
(
i
)
{
}
int
bar
()
{
return
i
;
}
int
i
;
};
struct
Base12a
:
Base1a
,
Base2a
{
Base12a
(
int
i
,
int
j
)
:
Base1a
(
i
),
Base2a
(
j
)
{
}
};
test_initializer
multiple_inheritance_nonexplicit
([](
py
::
module
&
m
)
{
py
::
class_
<
Base1a
,
std
::
shared_ptr
<
Base1a
>>
(
m
,
"Base1a"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
"foo"
,
&
Base1a
::
foo
);
py
::
class_
<
Base2a
,
std
::
shared_ptr
<
Base2a
>>
(
m
,
"Base2a"
)
.
def
(
py
::
init
<
int
>
())
.
def
(
"bar"
,
&
Base2a
::
bar
);
py
::
class_
<
Base12a
,
/* Base1 missing */
Base2a
,
std
::
shared_ptr
<
Base12a
>>
(
m
,
"Base12a"
,
py
::
multiple_inheritance
())
.
def
(
py
::
init
<
int
,
int
>
());
m
.
def
(
"bar_base2a"
,
[](
Base2a
*
b
)
{
return
b
->
bar
();
});
m
.
def
(
"bar_base2a_sharedptr"
,
[](
std
::
shared_ptr
<
Base2a
>
b
)
{
return
b
->
bar
();
});
});
tests/test_multiple_inheritance.py
0 → 100644
View file @
8e5dceb6
import
pytest
def
test_multiple_inheritance_cpp
(
msg
):
from
pybind11_tests
import
MIType
mt
=
MIType
(
3
,
4
)
assert
mt
.
foo
()
==
3
assert
mt
.
bar
()
==
4
def
test_multiple_inheritance_mix1
(
msg
):
from
pybind11_tests
import
Base2
class
Base1
:
def
__init__
(
self
,
i
):
self
.
i
=
i
def
foo
(
self
):
return
self
.
i
class
MITypePy
(
Base1
,
Base2
):
def
__init__
(
self
,
i
,
j
):
Base1
.
__init__
(
self
,
i
)
Base2
.
__init__
(
self
,
j
)
mt
=
MITypePy
(
3
,
4
)
assert
mt
.
foo
()
==
3
assert
mt
.
bar
()
==
4
def
test_multiple_inheritance_mix2
(
msg
):
from
pybind11_tests
import
Base1
class
Base2
:
def
__init__
(
self
,
i
):
self
.
i
=
i
def
bar
(
self
):
return
self
.
i
class
MITypePy
(
Base1
,
Base2
):
def
__init__
(
self
,
i
,
j
):
Base1
.
__init__
(
self
,
i
)
Base2
.
__init__
(
self
,
j
)
mt
=
MITypePy
(
3
,
4
)
assert
mt
.
foo
()
==
3
assert
mt
.
bar
()
==
4
def
test_multiple_inheritance_virtbase
(
msg
):
from
pybind11_tests
import
Base12a
,
bar_base2a
,
bar_base2a_sharedptr
class
MITypePy
(
Base12a
):
def
__init__
(
self
,
i
,
j
):
Base12a
.
__init__
(
self
,
i
,
j
)
mt
=
MITypePy
(
3
,
4
)
assert
mt
.
bar
()
==
4
assert
bar_base2a
(
mt
)
==
4
assert
bar_base2a_sharedptr
(
mt
)
==
4
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment