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
4e959c9a
Commit
4e959c9a
authored
Dec 08, 2016
by
Dean Moldovan
Committed by
Wenzel Jakob
Dec 08, 2016
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add syntax sugar for resolving overloaded functions (#541)
parent
ae185b7f
Hide whitespace changes
Inline
Side-by-side
Showing
6 changed files
with
101 additions
and
2 deletions
+101
-2
docs/classes.rst
+31
-2
include/pybind11/common.h
+35
-0
tests/test_constants_and_functions.cpp
+11
-0
tests/test_constants_and_functions.py
+3
-0
tests/test_methods_and_attributes.cpp
+16
-0
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:
...
@@ -104,6 +104,8 @@ With the above change, the same Python code now produces the following output:
>>> print(p)
>>> print(p)
<example.Pet named 'Molly'>
<example.Pet named 'Molly'>
.. [#f1] Stateless closures are those with an empty pair of brackets ``[]`` as the capture object.
.. _properties:
.. _properties:
Instance and static fields
Instance and static fields
...
@@ -337,6 +339,35 @@ The overload signatures are also visible in the method's docstring:
...
@@ -337,6 +339,35 @@ The overload signatures are also visible in the method's docstring:
|
|
| Set the pet's name
| 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::
.. note::
To define multiple overloaded constructors, simply declare one after the
To define multiple overloaded constructors, simply declare one after the
...
@@ -406,5 +437,3 @@ typed enums.
...
@@ -406,5 +437,3 @@ typed enums.
...
...
By default, these are omitted to conserve space.
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, "?");
...
@@ -557,4 +557,39 @@ PYBIND11_DECL_FMT(bool, "?");
/// Dummy destructor wrapper that can be used to expose classes with a private destructor
/// Dummy destructor wrapper that can be used to expose classes with a private destructor
struct
nodelete
{
template
<
typename
T
>
void
operator
()(
T
*
)
{
}
};
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
)
NAMESPACE_END
(
pybind11
)
tests/test_constants_and_functions.cpp
View file @
4e959c9a
...
@@ -23,6 +23,9 @@ std::string test_function3(int i) {
...
@@ -23,6 +23,9 @@ std::string test_function3(int i) {
return
"test_function("
+
std
::
to_string
(
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
()
{
py
::
bytes
return_bytes
()
{
const
char
*
data
=
"
\x01\x00\x02\x00
"
;
const
char
*
data
=
"
\x01\x00\x02\x00
"
;
return
std
::
string
(
data
,
4
);
return
std
::
string
(
data
,
4
);
...
@@ -45,6 +48,14 @@ test_initializer constants_and_functions([](py::module &m) {
...
@@ -45,6 +48,14 @@ test_initializer constants_and_functions([](py::module &m) {
m
.
def
(
"test_function"
,
&
test_function2
);
m
.
def
(
"test_function"
,
&
test_function2
);
m
.
def
(
"test_function"
,
&
test_function3
);
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"
)
py
::
enum_
<
MyEnum
>
(
m
,
"MyEnum"
)
.
value
(
"EFirstEntry"
,
EFirstEntry
)
.
value
(
"EFirstEntry"
,
EFirstEntry
)
.
value
(
"ESecondEntry"
,
ESecondEntry
)
.
value
(
"ESecondEntry"
,
ESecondEntry
)
...
...
tests/test_constants_and_functions.py
View file @
4e959c9a
...
@@ -14,6 +14,9 @@ def test_function_overloading():
...
@@ -14,6 +14,9 @@ def test_function_overloading():
assert
test_function
(
MyEnum
.
EFirstEntry
)
==
"test_function(enum=1)"
assert
test_function
(
MyEnum
.
EFirstEntry
)
==
"test_function(enum=1)"
assert
test_function
(
MyEnum
.
ESecondEntry
)
==
"test_function(enum=2)"
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
():
def
test_bytes
():
from
pybind11_tests
import
return_bytes
,
print_bytes
from
pybind11_tests
import
return_bytes
,
print_bytes
...
...
tests/test_methods_and_attributes.cpp
View file @
4e959c9a
...
@@ -50,6 +50,11 @@ public:
...
@@ -50,6 +50,11 @@ public:
int
*
internal4
()
{
return
&
value
;
}
// return by pointer
int
*
internal4
()
{
return
&
value
;
}
// return by pointer
const
int
*
internal5
()
{
return
&
value
;
}
// return by const 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
;
int
value
=
0
;
};
};
...
@@ -117,6 +122,17 @@ test_initializer methods_and_attributes([](py::module &m) {
...
@@ -117,6 +122,17 @@ test_initializer methods_and_attributes([](py::module &m) {
.
def
(
"internal3"
,
&
ExampleMandA
::
internal3
)
.
def
(
"internal3"
,
&
ExampleMandA
::
internal3
)
.
def
(
"internal4"
,
&
ExampleMandA
::
internal4
)
.
def
(
"internal4"
,
&
ExampleMandA
::
internal4
)
.
def
(
"internal5"
,
&
ExampleMandA
::
internal5
)
.
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
(
"__str__"
,
&
ExampleMandA
::
toString
)
.
def_readwrite
(
"value"
,
&
ExampleMandA
::
value
)
.
def_readwrite
(
"value"
,
&
ExampleMandA
::
value
)
;
;
...
...
tests/test_methods_and_attributes.py
View file @
4e959c9a
...
@@ -31,6 +31,11 @@ def test_methods_and_attributes():
...
@@ -31,6 +31,11 @@ def test_methods_and_attributes():
assert
instance1
.
internal4
()
==
320
assert
instance1
.
internal4
()
==
320
assert
instance1
.
internal5
()
==
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
assert
instance1
.
value
==
320
instance1
.
value
=
100
instance1
.
value
=
100
assert
str
(
instance1
)
==
"ExampleMandA[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