mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-29 00:22:00 +00:00
Revert noexcept deduction in favour of better SFINAE on lambda functions (#677)
noexcept deduction, added in PR #555, doesn't work with clang's -std=c++1z; and while it works with g++, it isn't entirely clear to me that it is required to work in C++17. What should work, however, is that C++17 allows implicit conversion of a `noexcept(true)` function pointer to a `noexcept(false)` (i.e. default, noexcept-not-specified) function pointer. That was breaking in pybind11 because the cpp_function template used for lambdas provided a better match (i.e. without requiring an implicit conversion), but it then failed. This commit takes a different approach of using SFINAE on the lambda function to prevent it from matching a non-lambda object, which then gets implicit conversion from a `noexcept` function pointer to a `noexcept(false)` function pointer. This much nicer solution also gets rid of the C++17 NOEXCEPT macros, and works in both clang and g++.
This commit is contained in:
parent
d361ea15fb
commit
1d7998e333
@ -202,17 +202,6 @@ extern "C" {
|
|||||||
} \
|
} \
|
||||||
PyObject *pybind11_init()
|
PyObject *pybind11_init()
|
||||||
|
|
||||||
// Function return value and argument type deduction support. When compiling under C++17 these
|
|
||||||
// differ as C++17 makes the noexcept specifier part of the function type, while it is not part of
|
|
||||||
// the type under earlier standards.
|
|
||||||
#ifdef __cpp_noexcept_function_type
|
|
||||||
# define PYBIND11_NOEXCEPT_TPL_ARG , bool NoExceptions
|
|
||||||
# define PYBIND11_NOEXCEPT_SPECIFIER noexcept(NoExceptions)
|
|
||||||
#else
|
|
||||||
# define PYBIND11_NOEXCEPT_TPL_ARG
|
|
||||||
# define PYBIND11_NOEXCEPT_SPECIFIER
|
|
||||||
#endif
|
|
||||||
|
|
||||||
NAMESPACE_BEGIN(pybind11)
|
NAMESPACE_BEGIN(pybind11)
|
||||||
|
|
||||||
using ssize_t = Py_ssize_t;
|
using ssize_t = Py_ssize_t;
|
||||||
@ -643,16 +632,16 @@ struct nodelete { template <typename T> void operator()(T*) { } };
|
|||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
struct overload_cast_impl {
|
struct overload_cast_impl {
|
||||||
template <typename Return /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return>
|
||||||
constexpr auto operator()(Return (*pf)(Args...) PYBIND11_NOEXCEPT_SPECIFIER) const noexcept
|
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
|
||||||
-> decltype(pf) { return pf; }
|
-> decltype(pf) { return pf; }
|
||||||
|
|
||||||
template <typename Return, typename Class /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename Class>
|
||||||
constexpr auto operator()(Return (Class::*pmf)(Args...) PYBIND11_NOEXCEPT_SPECIFIER, std::false_type = {}) const noexcept
|
constexpr auto operator()(Return (Class::*pmf)(Args...), std::false_type = {}) const noexcept
|
||||||
-> decltype(pmf) { return pmf; }
|
-> decltype(pmf) { return pmf; }
|
||||||
|
|
||||||
template <typename Return, typename Class /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename Class>
|
||||||
constexpr auto operator()(Return (Class::*pmf)(Args...) const PYBIND11_NOEXCEPT_SPECIFIER, std::true_type) const noexcept
|
constexpr auto operator()(Return (Class::*pmf)(Args...) const, std::true_type) const noexcept
|
||||||
-> decltype(pmf) { return pmf; }
|
-> decltype(pmf) { return pmf; }
|
||||||
};
|
};
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
@ -15,11 +15,11 @@
|
|||||||
NAMESPACE_BEGIN(pybind11)
|
NAMESPACE_BEGIN(pybind11)
|
||||||
NAMESPACE_BEGIN(detail)
|
NAMESPACE_BEGIN(detail)
|
||||||
|
|
||||||
template <typename Return, typename... Args /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename... Args>
|
||||||
struct type_caster<std::function<Return(Args...) PYBIND11_NOEXCEPT_SPECIFIER>> {
|
struct type_caster<std::function<Return(Args...)>> {
|
||||||
using type = std::function<Return(Args...) PYBIND11_NOEXCEPT_SPECIFIER>;
|
using type = std::function<Return(Args...)>;
|
||||||
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
using retval_type = conditional_t<std::is_same<Return, void>::value, void_type, Return>;
|
||||||
using function_type = Return (*) (Args...) PYBIND11_NOEXCEPT_SPECIFIER;
|
using function_type = Return (*) (Args...);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool load(handle src_, bool) {
|
bool load(handle src_, bool) {
|
||||||
|
@ -1140,23 +1140,22 @@ template <typename T, int Flags> struct handle_type_name<array_t<T, Flags>> {
|
|||||||
|
|
||||||
NAMESPACE_END(detail)
|
NAMESPACE_END(detail)
|
||||||
|
|
||||||
template <typename Func, typename Return, typename... Args /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Func, typename Return, typename... Args>
|
||||||
detail::vectorize_helper<Func, Return, Args...>
|
detail::vectorize_helper<Func, Return, Args...>
|
||||||
vectorize(const Func &f, Return (*) (Args ...) PYBIND11_NOEXCEPT_SPECIFIER) {
|
vectorize(const Func &f, Return (*) (Args ...)) {
|
||||||
return detail::vectorize_helper<Func, Return, Args...>(f);
|
return detail::vectorize_helper<Func, Return, Args...>(f);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Return, typename... Args /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename... Args>
|
||||||
detail::vectorize_helper<Return (*) (Args ...) PYBIND11_NOEXCEPT_SPECIFIER, Return, Args...>
|
detail::vectorize_helper<Return (*) (Args ...), Return, Args...>
|
||||||
vectorize(Return (*f) (Args ...) PYBIND11_NOEXCEPT_SPECIFIER) {
|
vectorize(Return (*f) (Args ...)) {
|
||||||
return vectorize<Return (*) (Args ...), Return, Args...>(f, f);
|
return vectorize<Return (*) (Args ...), Return, Args...>(f, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Func>
|
template <typename Func, typename FuncType = typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type>
|
||||||
auto vectorize(Func &&f) -> decltype(
|
auto vectorize(Func &&f) -> decltype(
|
||||||
vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type *) nullptr)) {
|
vectorize(std::forward<Func>(f), (FuncType *) nullptr)) {
|
||||||
return vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype(
|
return vectorize(std::forward<Func>(f), (FuncType *) nullptr);
|
||||||
&std::remove_reference<Func>::type::operator())>::type *) nullptr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
NAMESPACE_END(pybind11)
|
NAMESPACE_END(pybind11)
|
||||||
|
@ -44,30 +44,31 @@ public:
|
|||||||
cpp_function() { }
|
cpp_function() { }
|
||||||
|
|
||||||
/// Construct a cpp_function from a vanilla function pointer
|
/// Construct a cpp_function from a vanilla function pointer
|
||||||
template <typename Return, typename... Args, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename... Args, typename... Extra>
|
||||||
cpp_function(Return (*f)(Args...) PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
cpp_function(Return (*f)(Args...), const Extra&... extra) {
|
||||||
initialize(f, f, extra...);
|
initialize(f, f, extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a cpp_function from a lambda function (possibly with internal state)
|
/// Construct a cpp_function from a lambda function (possibly with internal state)
|
||||||
template <typename Func, typename... Extra> cpp_function(Func &&f, const Extra&... extra) {
|
template <typename Func, typename... Extra,
|
||||||
|
typename FuncType = typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type>
|
||||||
|
cpp_function(Func &&f, const Extra&... extra) {
|
||||||
initialize(std::forward<Func>(f),
|
initialize(std::forward<Func>(f),
|
||||||
(typename detail::remove_class<decltype(
|
(FuncType *) nullptr, extra...);
|
||||||
&std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a cpp_function from a class method (non-const)
|
/// Construct a cpp_function from a class method (non-const)
|
||||||
template <typename Return, typename Class, typename... Arg, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename Class, typename... Arg, typename... Extra>
|
||||||
cpp_function(Return (Class::*f)(Arg...) PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) {
|
||||||
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
|
initialize([f](Class *c, Arg... args) -> Return { return (c->*f)(args...); },
|
||||||
(Return (*) (Class *, Arg...) PYBIND11_NOEXCEPT_SPECIFIER) nullptr, extra...);
|
(Return (*) (Class *, Arg...)) nullptr, extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a cpp_function from a class method (const)
|
/// Construct a cpp_function from a class method (const)
|
||||||
template <typename Return, typename Class, typename... Arg, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Return, typename Class, typename... Arg, typename... Extra>
|
||||||
cpp_function(Return (Class::*f)(Arg...) const PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) {
|
||||||
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
|
initialize([f](const Class *c, Arg... args) -> Return { return (c->*f)(args...); },
|
||||||
(Return (*)(const Class *, Arg ...) PYBIND11_NOEXCEPT_SPECIFIER) nullptr, extra...);
|
(Return (*)(const Class *, Arg ...)) nullptr, extra...);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the function name
|
/// Return the function name
|
||||||
@ -80,8 +81,8 @@ protected:
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Special internal constructor for functors, lambda functions, etc.
|
/// Special internal constructor for functors, lambda functions, etc.
|
||||||
template <typename Func, typename Return, typename... Args, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
template <typename Func, typename Return, typename... Args, typename... Extra>
|
||||||
void initialize(Func &&f, Return (*)(Args...) PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
|
||||||
|
|
||||||
struct capture { typename std::remove_reference<Func>::type f; };
|
struct capture { typename std::remove_reference<Func>::type f; };
|
||||||
|
|
||||||
@ -162,7 +163,7 @@ protected:
|
|||||||
if (cast_in::has_kwargs) rec->has_kwargs = true;
|
if (cast_in::has_kwargs) rec->has_kwargs = true;
|
||||||
|
|
||||||
/* Stash some additional information used by an important optimization in 'functional.h' */
|
/* Stash some additional information used by an important optimization in 'functional.h' */
|
||||||
using FunctionType = Return (*)(Args...) PYBIND11_NOEXCEPT_SPECIFIER;
|
using FunctionType = Return (*)(Args...);
|
||||||
constexpr bool is_function_ptr =
|
constexpr bool is_function_ptr =
|
||||||
std::is_convertible<Func, FunctionType>::value &&
|
std::is_convertible<Func, FunctionType>::value &&
|
||||||
sizeof(capture) == sizeof(void *);
|
sizeof(capture) == sizeof(void *);
|
||||||
|
Loading…
Reference in New Issue
Block a user