Skip to content
GitLab
Menu
Projects
Groups
Snippets
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
Menu
Open sidebar
gaoqiong
pybind11
Commits
4e959c9a
Commit
4e959c9a
authored
Dec 08, 2016
by
Dean Moldovan
Committed by
Wenzel Jakob
Dec 08, 2016
Browse files
Add syntax sugar for resolving overloaded functions (#541)
parent
ae185b7f
Changes
6
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
101 additions
and
2 deletions
+101
-2
docs/classes.rst
docs/classes.rst
+31
-2
include/pybind11/common.h
include/pybind11/common.h
+35
-0
tests/test_constants_and_functions.cpp
tests/test_constants_and_functions.cpp
+11
-0
tests/test_constants_and_functions.py
tests/test_constants_and_functions.py
+3
-0
tests/test_methods_and_attributes.cpp
tests/test_methods_and_attributes.cpp
+16
-0
tests/test_methods_and_attributes.py
tests/test_methods_and_attributes.py
+5
-0
No files found.
docs/classes.rst
View file @
4e959c9a
...
...
@@ -104,6 +104,8 @@ With the above change, the same Python code now produces the following output:
>>> print(p)
<example.Pet named 'Molly'>
.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object.
.. _properties:
Instance and static fields
...
...
@@ -337,6 +339,35 @@ The overload signatures are also visible in the method's docstring:
|
| Set the pet's name
If you have a C++14 compatible compiler [#cpp14]_, you can use an alternative
syntax to cast the overloaded function:
.. code-block:: cpp
py::class_<Pet>(m, "Pet")
.def("set", py::overload_cast<int>(&Pet::set), "Set the pet's age")
.def("set", py::overload_cast<const std::string &>(&Pet::set), "Set the pet's name");
Here, ``py::overload_cast`` only requires the parameter types to be specified.
The return type and class are deduced. This avoids the additional noise of
``void (Pet::*)()`` as seen in the raw cast. If a function is overloaded based
on constness, the ``py::const_`` tag should be used:
.. code-block:: cpp
struct Widget {
int foo(int x, float y);
int foo(int x, float y) const;
};
py::class_<Widget>(m, "Widget")
.def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
.def("foo_const", py::overload_cast<int, float>(&Widget::foo, py::const_));
.. [#cpp14] A compiler which supports the ``-std=c++14`` flag
or Visual Studio 2015 Update 2 and newer.
.. note::
To define multiple overloaded constructors, simply declare one after the
...
...
@@ -406,5 +437,3 @@ typed enums.
...
By default, these are omitted to conserve space.
.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object.
include/pybind11/common.h
View file @
4e959c9a
...
...
@@ -557,4 +557,39 @@ PYBIND11_DECL_FMT(bool, "?");
/// Dummy destructor wrapper that can be used to expose classes with a private destructor
struct
nodelete
{
template
<
typename
T
>
void
operator
()(
T
*
)
{
}
};
// overload_cast requires variable templates: C++14 or MSVC 2015 Update 2
#if defined(PYBIND11_CPP14) || _MSC_FULL_VER >= 190023918
#define PYBIND11_OVERLOAD_CAST 1
NAMESPACE_BEGIN
(
detail
)
template
<
typename
...
Args
>
struct
overload_cast_impl
{
template
<
typename
Return
>
constexpr
auto
operator
()(
Return
(
*
pf
)(
Args
...))
const
noexcept
->
decltype
(
pf
)
{
return
pf
;
}
template
<
typename
Return
,
typename
Class
>
constexpr
auto
operator
()(
Return
(
Class
::*
pmf
)(
Args
...),
std
::
false_type
=
{})
const
noexcept
->
decltype
(
pmf
)
{
return
pmf
;
}
template
<
typename
Return
,
typename
Class
>
constexpr
auto
operator
()(
Return
(
Class
::*
pmf
)(
Args
...)
const
,
std
::
true_type
)
const
noexcept
->
decltype
(
pmf
)
{
return
pmf
;
}
};
NAMESPACE_END
(
detail
)
/// Syntax sugar for resolving overloaded function pointers:
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
template
<
typename
...
Args
>
static
constexpr
detail
::
overload_cast_impl
<
Args
...
>
overload_cast
=
{};
// MSVC 2015 only accepts this particular initialization syntax for this variable template.
/// Const member function selector for overload_cast
/// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)
/// - sweet: overload_cast<Arg>(&Class::func, const_)
static
constexpr
auto
const_
=
std
::
true_type
{};
#endif // overload_cast
NAMESPACE_END
(
pybind11
)
tests/test_constants_and_functions.cpp
View file @
4e959c9a
...
...
@@ -23,6 +23,9 @@ std::string test_function3(int i) {
return
"test_function("
+
std
::
to_string
(
i
)
+
")"
;
}
py
::
str
test_function4
(
int
,
float
)
{
return
"test_function(int, float)"
;
}
py
::
str
test_function4
(
float
,
int
)
{
return
"test_function(float, int)"
;
}
py
::
bytes
return_bytes
()
{
const
char
*
data
=
"
\x01\x00\x02\x00
"
;
return
std
::
string
(
data
,
4
);
...
...
@@ -45,6 +48,14 @@ test_initializer constants_and_functions([](py::module &m) {
m
.
def
(
"test_function"
,
&
test_function2
);
m
.
def
(
"test_function"
,
&
test_function3
);
#if defined(PYBIND11_OVERLOAD_CAST)
m
.
def
(
"test_function"
,
py
::
overload_cast
<
int
,
float
>
(
&
test_function4
));
m
.
def
(
"test_function"
,
py
::
overload_cast
<
float
,
int
>
(
&
test_function4
));
#else
m
.
def
(
"test_function"
,
static_cast
<
py
::
str
(
*
)(
int
,
float
)
>
(
&
test_function4
));
m
.
def
(
"test_function"
,
static_cast
<
py
::
str
(
*
)(
float
,
int
)
>
(
&
test_function4
));
#endif
py
::
enum_
<
MyEnum
>
(
m
,
"MyEnum"
)
.
value
(
"EFirstEntry"
,
EFirstEntry
)
.
value
(
"ESecondEntry"
,
ESecondEntry
)
...
...
tests/test_constants_and_functions.py
View file @
4e959c9a
...
...
@@ -14,6 +14,9 @@ def test_function_overloading():
assert
test_function
(
MyEnum
.
EFirstEntry
)
==
"test_function(enum=1)"
assert
test_function
(
MyEnum
.
ESecondEntry
)
==
"test_function(enum=2)"
assert
test_function
(
1
,
1.0
)
==
"test_function(int, float)"
assert
test_function
(
2.0
,
2
)
==
"test_function(float, int)"
def
test_bytes
():
from
pybind11_tests
import
return_bytes
,
print_bytes
...
...
tests/test_methods_and_attributes.cpp
View file @
4e959c9a
...
...
@@ -50,6 +50,11 @@ public:
int
*
internal4
()
{
return
&
value
;
}
// return by pointer
const
int
*
internal5
()
{
return
&
value
;
}
// return by const pointer
py
::
str
overloaded
(
int
,
float
)
{
return
"(int, float)"
;
}
py
::
str
overloaded
(
float
,
int
)
{
return
"(float, int)"
;
}
py
::
str
overloaded
(
int
,
float
)
const
{
return
"(int, float) const"
;
}
py
::
str
overloaded
(
float
,
int
)
const
{
return
"(float, int) const"
;
}
int
value
=
0
;
};
...
...
@@ -117,6 +122,17 @@ test_initializer methods_and_attributes([](py::module &m) {
.
def
(
"internal3"
,
&
ExampleMandA
::
internal3
)
.
def
(
"internal4"
,
&
ExampleMandA
::
internal4
)
.
def
(
"internal5"
,
&
ExampleMandA
::
internal5
)
#if defined(PYBIND11_OVERLOAD_CAST)
.
def
(
"overloaded"
,
py
::
overload_cast
<
int
,
float
>
(
&
ExampleMandA
::
overloaded
))
.
def
(
"overloaded"
,
py
::
overload_cast
<
float
,
int
>
(
&
ExampleMandA
::
overloaded
))
.
def
(
"overloaded_const"
,
py
::
overload_cast
<
int
,
float
>
(
&
ExampleMandA
::
overloaded
,
py
::
const_
))
.
def
(
"overloaded_const"
,
py
::
overload_cast
<
float
,
int
>
(
&
ExampleMandA
::
overloaded
,
py
::
const_
))
#else
.
def
(
"overloaded"
,
static_cast
<
py
::
str
(
ExampleMandA
::*
)(
int
,
float
)
>
(
&
ExampleMandA
::
overloaded
))
.
def
(
"overloaded"
,
static_cast
<
py
::
str
(
ExampleMandA
::*
)(
float
,
int
)
>
(
&
ExampleMandA
::
overloaded
))
.
def
(
"overloaded_const"
,
static_cast
<
py
::
str
(
ExampleMandA
::*
)(
int
,
float
)
const
>
(
&
ExampleMandA
::
overloaded
))
.
def
(
"overloaded_const"
,
static_cast
<
py
::
str
(
ExampleMandA
::*
)(
float
,
int
)
const
>
(
&
ExampleMandA
::
overloaded
))
#endif
.
def
(
"__str__"
,
&
ExampleMandA
::
toString
)
.
def_readwrite
(
"value"
,
&
ExampleMandA
::
value
)
;
...
...
tests/test_methods_and_attributes.py
View file @
4e959c9a
...
...
@@ -31,6 +31,11 @@ def test_methods_and_attributes():
assert
instance1
.
internal4
()
==
320
assert
instance1
.
internal5
()
==
320
assert
instance1
.
overloaded
(
1
,
1.0
)
==
"(int, float)"
assert
instance1
.
overloaded
(
2.0
,
2
)
==
"(float, int)"
assert
instance1
.
overloaded_const
(
3
,
3.0
)
==
"(int, float) const"
assert
instance1
.
overloaded_const
(
4.0
,
4
)
==
"(float, int) const"
assert
instance1
.
value
==
320
instance1
.
value
=
100
assert
str
(
instance1
)
==
"ExampleMandA[value=100]"
...
...
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