Make overload_cast_impl available in C++11 mode. (#1581)

* Make `overload_cast_impl` available in C++11 mode.

Narrow the scope of the `#if defined(PYBIND11_CPP14)` block around overload_cast to only
cover the parts where C++14 is stricly required. Thus, the implementation in
`pybind11::details::overload_cast_impl` is still available in C++11 mode.

* PR #1581: Modify test to use overload_cast_impl, update docs and change log
This commit is contained in:
Andre Schmeißer 2019-08-19 12:54:33 +02:00 committed by Wenzel Jakob
parent 04c8f4b56e
commit 19189b4c2c
4 changed files with 31 additions and 13 deletions

View File

@ -10,7 +10,9 @@ Starting with version 1.8.0, pybind11 releases use a `semantic versioning
v2.3.1 (Not yet released) v2.3.1 (Not yet released)
----------------------------------------------------- -----------------------------------------------------
* TBA * ``py::details::overload_cast_impl`` is available in C++11 mode, can be used
like ``overload_cast`` with an additional set of parantheses.
`1581 <https://github.com/pybind/pybind11/pull/1581>`_.
v2.3.0 (June 11, 2019) v2.3.0 (June 11, 2019)
----------------------------------------------------- -----------------------------------------------------
@ -105,7 +107,6 @@ v2.3.0 (June 11, 2019)
`#1744 <https://github.com/pybind/pybind11/pull/1744>`_, `#1744 <https://github.com/pybind/pybind11/pull/1744>`_,
`#1670 <https://github.com/pybind/pybind11/pull/1670>`_. `#1670 <https://github.com/pybind/pybind11/pull/1670>`_.
v2.2.4 (September 11, 2018) v2.2.4 (September 11, 2018)
----------------------------------------------------- -----------------------------------------------------

View File

@ -422,6 +422,17 @@ on constness, the ``py::const_`` tag should be used:
.def("foo_mutable", py::overload_cast<int, float>(&Widget::foo)) .def("foo_mutable", py::overload_cast<int, float>(&Widget::foo))
.def("foo_const", py::overload_cast<int, float>(&Widget::foo, py::const_)); .def("foo_const", py::overload_cast<int, float>(&Widget::foo, py::const_));
If you prefer the ``py::overload_cast`` syntax but have a C++11 compatible compiler only,
you can use ``py::detail::overload_cast_impl`` with an additional set of parentheses:
.. code-block:: cpp
template <typename... Args>
using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
py::class_<Pet>(m, "Pet")
.def("set", overload_cast_<int>()(&Pet::set), "Set the pet's age")
.def("set", overload_cast_<const std::string &>()(&Pet::set), "Set the pet's name");
.. [#cpp14] A compiler which supports the ``-std=c++14`` flag .. [#cpp14] A compiler which supports the ``-std=c++14`` flag
or Visual Studio 2015 Update 2 and newer. or Visual Studio 2015 Update 2 and newer.

View File

@ -720,10 +720,6 @@ struct error_scope {
/// 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
#if defined(PYBIND11_CPP14)
#define PYBIND11_OVERLOAD_CAST 1
NAMESPACE_BEGIN(detail) NAMESPACE_BEGIN(detail)
template <typename... Args> template <typename... Args>
struct overload_cast_impl { struct overload_cast_impl {
@ -743,19 +739,23 @@ struct overload_cast_impl {
}; };
NAMESPACE_END(detail) NAMESPACE_END(detail)
// overload_cast requires variable templates: C++14
#if defined(PYBIND11_CPP14)
#define PYBIND11_OVERLOAD_CAST 1
/// Syntax sugar for resolving overloaded function pointers: /// Syntax sugar for resolving overloaded function pointers:
/// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func) /// - regular: static_cast<Return (Class::*)(Arg0, Arg1, Arg2)>(&Class::func)
/// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func) /// - sweet: overload_cast<Arg0, Arg1, Arg2>(&Class::func)
template <typename... Args> template <typename... Args>
static constexpr detail::overload_cast_impl<Args...> overload_cast = {}; static constexpr detail::overload_cast_impl<Args...> overload_cast = {};
// MSVC 2015 only accepts this particular initialization syntax for this variable template. // MSVC 2015 only accepts this particular initialization syntax for this variable template.
#endif
/// Const member function selector for overload_cast /// Const member function selector for overload_cast
/// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func) /// - regular: static_cast<Return (Class::*)(Arg) const>(&Class::func)
/// - sweet: overload_cast<Arg>(&Class::func, const_) /// - sweet: overload_cast<Arg>(&Class::func, const_)
static constexpr auto const_ = std::true_type{}; static constexpr auto const_ = std::true_type{};
#else // no overload_cast: providing something that static_assert-fails: #if !defined(PYBIND11_CPP14) // no overload_cast: providing something that static_assert-fails:
template <typename... Args> struct overload_cast { template <typename... Args> struct overload_cast {
static_assert(detail::deferred_t<std::false_type, Args...>::value, static_assert(detail::deferred_t<std::false_type, Args...>::value,
"pybind11::overload_cast<...> requires compiling in C++14 mode"); "pybind11::overload_cast<...> requires compiling in C++14 mode");

View File

@ -11,6 +11,11 @@
#include "pybind11_tests.h" #include "pybind11_tests.h"
#include "constructor_stats.h" #include "constructor_stats.h"
#if !defined(PYBIND11_OVERLOAD_CAST)
template <typename... Args>
using overload_cast_ = pybind11::detail::overload_cast_impl<Args...>;
#endif
class ExampleMandA { class ExampleMandA {
public: public:
ExampleMandA() { print_default_created(this); } ExampleMandA() { print_default_created(this); }
@ -242,15 +247,16 @@ TEST_SUBMODULE(methods_and_attributes, m) {
.def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<int, int>(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_)) .def("overloaded_const", py::overload_cast<float, float>(&ExampleMandA::overloaded, py::const_))
#else #else
.def("overloaded", static_cast<py::str (ExampleMandA::*)()>(&ExampleMandA::overloaded)) // Use both the traditional static_cast method and the C++11 compatible overload_cast_
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int)>(&ExampleMandA::overloaded)) .def("overloaded", overload_cast_<>()(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, float)>(&ExampleMandA::overloaded)) .def("overloaded", overload_cast_<int>()(&ExampleMandA::overloaded))
.def("overloaded", overload_cast_<int, float>()(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, int)>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(int, int)>(&ExampleMandA::overloaded))
.def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded)) .def("overloaded", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded))
.def("overloaded_float", static_cast<py::str (ExampleMandA::*)(float, float)>(&ExampleMandA::overloaded)) .def("overloaded_float", overload_cast_<float, float>()(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int ) const>(&ExampleMandA::overloaded)) .def("overloaded_const", overload_cast_<int >()(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, float) const>(&ExampleMandA::overloaded)) .def("overloaded_const", overload_cast_<int, float>()(&ExampleMandA::overloaded, py::const_))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, int) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(int, int) const>(&ExampleMandA::overloaded))
.def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded)) .def("overloaded_const", static_cast<py::str (ExampleMandA::*)(float, float) const>(&ExampleMandA::overloaded))