mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-11 08:03:55 +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()
|
||||
|
||||
// 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)
|
||||
|
||||
using ssize_t = Py_ssize_t;
|
||||
@ -643,16 +632,16 @@ struct nodelete { template <typename T> void operator()(T*) { } };
|
||||
NAMESPACE_BEGIN(detail)
|
||||
template <typename... Args>
|
||||
struct overload_cast_impl {
|
||||
template <typename Return /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
constexpr auto operator()(Return (*pf)(Args...) PYBIND11_NOEXCEPT_SPECIFIER) const noexcept
|
||||
template <typename Return>
|
||||
constexpr auto operator()(Return (*pf)(Args...)) const noexcept
|
||||
-> decltype(pf) { return pf; }
|
||||
|
||||
template <typename Return, typename Class /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
constexpr auto operator()(Return (Class::*pmf)(Args...) PYBIND11_NOEXCEPT_SPECIFIER, std::false_type = {}) const noexcept
|
||||
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 /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
constexpr auto operator()(Return (Class::*pmf)(Args...) const PYBIND11_NOEXCEPT_SPECIFIER, std::true_type) const noexcept
|
||||
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)
|
||||
|
@ -15,11 +15,11 @@
|
||||
NAMESPACE_BEGIN(pybind11)
|
||||
NAMESPACE_BEGIN(detail)
|
||||
|
||||
template <typename Return, typename... Args /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
struct type_caster<std::function<Return(Args...) PYBIND11_NOEXCEPT_SPECIFIER>> {
|
||||
using type = std::function<Return(Args...) PYBIND11_NOEXCEPT_SPECIFIER>;
|
||||
template <typename Return, typename... Args>
|
||||
struct type_caster<std::function<Return(Args...)>> {
|
||||
using type = std::function<Return(Args...)>;
|
||||
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:
|
||||
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)
|
||||
|
||||
template <typename Func, typename Return, typename... Args /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
template <typename Func, typename Return, typename... 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);
|
||||
}
|
||||
|
||||
template <typename Return, typename... Args /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
detail::vectorize_helper<Return (*) (Args ...) PYBIND11_NOEXCEPT_SPECIFIER, Return, Args...>
|
||||
vectorize(Return (*f) (Args ...) PYBIND11_NOEXCEPT_SPECIFIER) {
|
||||
template <typename Return, typename... Args>
|
||||
detail::vectorize_helper<Return (*) (Args ...), Return, Args...>
|
||||
vectorize(Return (*f) (Args ...)) {
|
||||
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(
|
||||
vectorize(std::forward<Func>(f), (typename detail::remove_class<decltype(&std::remove_reference<Func>::type::operator())>::type *) nullptr)) {
|
||||
return 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), (FuncType *) nullptr);
|
||||
}
|
||||
|
||||
NAMESPACE_END(pybind11)
|
||||
|
@ -44,30 +44,31 @@ public:
|
||||
cpp_function() { }
|
||||
|
||||
/// Construct a cpp_function from a vanilla function pointer
|
||||
template <typename Return, typename... Args, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
cpp_function(Return (*f)(Args...) PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
||||
template <typename Return, typename... Args, typename... Extra>
|
||||
cpp_function(Return (*f)(Args...), const Extra&... extra) {
|
||||
initialize(f, f, extra...);
|
||||
}
|
||||
|
||||
/// 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),
|
||||
(typename detail::remove_class<decltype(
|
||||
&std::remove_reference<Func>::type::operator())>::type *) nullptr, extra...);
|
||||
(FuncType *) nullptr, extra...);
|
||||
}
|
||||
|
||||
/// Construct a cpp_function from a class method (non-const)
|
||||
template <typename Return, typename Class, typename... Arg, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
cpp_function(Return (Class::*f)(Arg...) PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
||||
template <typename Return, typename Class, typename... Arg, typename... Extra>
|
||||
cpp_function(Return (Class::*f)(Arg...), const Extra&... extra) {
|
||||
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)
|
||||
template <typename Return, typename Class, typename... Arg, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
cpp_function(Return (Class::*f)(Arg...) const PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
||||
template <typename Return, typename Class, typename... Arg, typename... Extra>
|
||||
cpp_function(Return (Class::*f)(Arg...) const, const Extra&... extra) {
|
||||
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
|
||||
@ -80,8 +81,8 @@ protected:
|
||||
}
|
||||
|
||||
/// Special internal constructor for functors, lambda functions, etc.
|
||||
template <typename Func, typename Return, typename... Args, typename... Extra /*,*/ PYBIND11_NOEXCEPT_TPL_ARG>
|
||||
void initialize(Func &&f, Return (*)(Args...) PYBIND11_NOEXCEPT_SPECIFIER, const Extra&... extra) {
|
||||
template <typename Func, typename Return, typename... Args, typename... Extra>
|
||||
void initialize(Func &&f, Return (*)(Args...), const Extra&... extra) {
|
||||
|
||||
struct capture { typename std::remove_reference<Func>::type f; };
|
||||
|
||||
@ -162,7 +163,7 @@ protected:
|
||||
if (cast_in::has_kwargs) rec->has_kwargs = true;
|
||||
|
||||
/* 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 =
|
||||
std::is_convertible<Func, FunctionType>::value &&
|
||||
sizeof(capture) == sizeof(void *);
|
||||
|
Loading…
Reference in New Issue
Block a user