diff --git a/include/pybind11/cast.h b/include/pybind11/cast.h index 535516b370..f0aa6e16c7 100644 --- a/include/pybind11/cast.h +++ b/include/pybind11/cast.h @@ -1004,23 +1004,24 @@ class type_caster::value>> : public pyobject_caste // - if the type is non-copy-constructible, the object must be the sole owner of the type (i.e. it // must have ref_count() == 1)h // If any of the above are not satisfied, we fall back to copying. -template struct move_is_plain_type : std::false_type {}; -template struct move_is_plain_type::value && !std::is_pointer::value && !std::is_reference::value && !std::is_const::value - >> : std::true_type { }; +template using move_is_plain_type = none_of< + std::is_void, std::is_pointer, std::is_reference, std::is_const +>; template struct move_always : std::false_type {}; -template struct move_always::value && - !std::is_copy_constructible::value && std::is_move_constructible::value && - std::is_same>().operator T&()), T&>::value - >> : std::true_type { }; +template struct move_always, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; template struct move_if_unreferenced : std::false_type {}; -template struct move_if_unreferenced::value && - !move_always::value && std::is_move_constructible::value && - std::is_same>().operator T&()), T&>::value - >> : std::true_type { }; -template using move_never = std::integral_constant::value && !move_if_unreferenced::value>; +template struct move_if_unreferenced, + negation>, + std::is_move_constructible, + std::is_same>().operator T&()), T&> +>::value>> : std::true_type {}; +template using move_never = none_of, move_if_unreferenced>; // Detect whether returning a `type` from a cast on type's type_caster is going to result in a // reference or pointer to a local variable of the type_caster. Basically, only @@ -1080,7 +1081,7 @@ template T handle::cast() const { return pybind11::cast(*this); template <> inline void handle::cast() const { return; } template -detail::enable_if_t::value || detail::move_if_unreferenced::value, T> move(object &&obj) { +detail::enable_if_t::value, T> move(object &&obj) { if (obj.ref_count() > 1) #if defined(NDEBUG) throw cast_error("Unable to cast Python instance to C++ rvalue: instance has multiple references" @@ -1427,14 +1428,14 @@ class unpacking_collector { /// Collect only positional arguments for a Python function call template ::value>> + typename = enable_if_t...>::value>> simple_collector collect_arguments(Args &&...args) { return simple_collector(std::forward(args)...); } /// Collect all arguments, including keywords and unpacking (only instantiated when needed) template ::value>> + typename = enable_if_t...>::value>> unpacking_collector collect_arguments(Args &&...args) { // Following argument order rules for generalized unpacking according to PEP 448 static_assert( diff --git a/include/pybind11/common.h b/include/pybind11/common.h index 712c1a5d62..eb34efff1a 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -345,8 +345,17 @@ struct internals { /// Return a reference to the current 'internals' information inline internals &get_internals(); -/// Index sequence for convenient template metaprogramming involving tuples +/// from __cpp_future__ import (convenient aliases from C++14/17) #ifdef PYBIND11_CPP14 +using std::enable_if_t; +using std::conditional_t; +#else +template using enable_if_t = typename std::enable_if::type; +template using conditional_t = typename std::conditional::type; +#endif + +/// Index sequences +#if defined(PYBIND11_CPP14) || defined(_MSC_VER) using std::index_sequence; using std::make_index_sequence; #else @@ -356,6 +365,32 @@ template struct make_index_sequence_impl <0, S...> { typedef index_ template using make_index_sequence = typename make_index_sequence_impl::type; #endif +#if defined(PYBIND11_CPP17) || defined(_MSC_VER) +using std::bool_constant; +using std::negation; +#else +template using bool_constant = std::integral_constant; +template using negation = bool_constant; +#endif + +/// Compile-time all/any/none of that check the ::value of all template types +#ifdef PYBIND11_CPP17 +template using all_of = bool_constant<(Ts::value && ...)>; +template using any_of = bool_constant<(Ts::value || ...)>; +#elif !defined(_MSC_VER) +template struct bools {}; +template using all_of = std::is_same< + bools, + bools>; +template using any_of = negation...>>; +#else +// MSVC has trouble with the above, but supports std::conjunction, which we can use instead (albeit +// at a slight loss of compilation efficiency). +template using all_of = std::conjunction; +template using any_of = std::disjunction; +#endif +template using none_of = negation>; + /// Strip the class from a method type template struct remove_class { }; template struct remove_class { typedef R type(A...); }; @@ -377,35 +412,11 @@ struct void_type { }; /// Helper template which holds a list of types template struct type_list { }; -/// from __cpp_future__ import (convenient aliases from C++14/17) -template using bool_constant = std::integral_constant; -template using negation = bool_constant; -template using enable_if_t = typename std::enable_if::type; -template using conditional_t = typename std::conditional::type; - /// Compile-time integer sum constexpr size_t constexpr_sum() { return 0; } template constexpr size_t constexpr_sum(T n, Ts... ns) { return size_t{n} + constexpr_sum(ns...); } -// Counts the number of types in the template parameter pack matching the predicate -#if !defined(_MSC_VER) -template class Predicate, typename... Ts> -using count_t = std::integral_constant::value...)>; -#else -// MSVC workaround (2015 Update 3 has issues with some member type aliases and constexpr) -template class Predicate, typename... Ts> struct count_t; -template class Predicate> struct count_t : std::integral_constant {}; -template class Predicate, class T, class... Ts> -struct count_t : std::integral_constant::value + count_t::value> {}; -#endif - -/// Return true if all/any Ts satify Predicate -template class Predicate, typename... Ts> -using all_of_t = bool_constant<(count_t::value == sizeof...(Ts))>; -template class Predicate, typename... Ts> -using any_of_t = bool_constant<(count_t::value > 0)>; - // Extracts the first type from the template parameter pack matching the predicate, or Default if none match. template class Predicate, class Default, class... Ts> struct first_of; template class Predicate, class Default> struct first_of { diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index 0a1208e16d..064587839e 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -42,9 +42,10 @@ template using is_eigen_ref = is_template_base_of using is_eigen_base = bool_constant< - is_template_base_of::value - && !is_eigen_dense::value && !is_eigen_sparse::value +template using is_eigen_base = all_of< + is_template_base_of, + negation>, + negation> >; template diff --git a/include/pybind11/pybind11.h b/include/pybind11/pybind11.h index 1db9efb8ce..afdb656ac5 100644 --- a/include/pybind11/pybind11.h +++ b/include/pybind11/pybind11.h @@ -924,12 +924,9 @@ class class_ : public detail::generic_type { template using is_holder = detail::is_holder_type; template using is_subtype = detail::bool_constant::value && !std::is_same::value>; template using is_base = detail::bool_constant::value && !std::is_same::value>; - template using is_valid_class_option = - detail::bool_constant< - is_holder::value || - is_subtype::value || - is_base::value - >; + // struct instead of using here to help MSVC: + template struct is_valid_class_option : + detail::any_of, is_subtype, is_base> {}; public: using type = type_; @@ -938,7 +935,7 @@ class class_ : public detail::generic_type { using holder_type = detail::first_of_t, options...>; using instance_type = detail::instance; - static_assert(detail::all_of_t::value, + static_assert(detail::all_of...>::value, "Unknown/invalid class_ template parameters provided"); PYBIND11_OBJECT(class_, generic_type, PyType_Check) diff --git a/include/pybind11/pytypes.h b/include/pybind11/pytypes.h index 2b49ecfc96..9753958664 100644 --- a/include/pybind11/pytypes.h +++ b/include/pybind11/pytypes.h @@ -410,12 +410,10 @@ class args_proxy : public handle { template using is_keyword = std::is_base_of; template using is_s_unpacking = std::is_same; // * unpacking template using is_ds_unpacking = std::is_same; // ** unpacking -template using is_positional = bool_constant< - !is_keyword::value && !is_s_unpacking::value && !is_ds_unpacking::value ->; -template using is_keyword_or_ds = bool_constant< - is_keyword::value || is_ds_unpacking::value +template using is_positional = none_of< + is_keyword, is_s_unpacking, is_ds_unpacking >; +template using is_keyword_or_ds = any_of, is_ds_unpacking>; // Call argument collector forward declarations template @@ -754,7 +752,7 @@ class dict : public object { if (!m_ptr) pybind11_fail("Could not allocate dict object!"); } template ::value>, + typename = detail::enable_if_t...>::value>, // MSVC workaround: it can't compile an out-of-line definition, so defer the collector typename collector = detail::deferred_t, Args...>> explicit dict(Args &&...args) : dict(collector(std::forward(args)...).kwargs()) { } diff --git a/include/pybind11/stl_bind.h b/include/pybind11/stl_bind.h index ef9950ebb1..d1d45e2c0b 100644 --- a/include/pybind11/stl_bind.h +++ b/include/pybind11/stl_bind.h @@ -253,8 +253,8 @@ void vector_modifiers(enable_if_t), // we have to access by copying; otherwise we return by reference. -template using vector_needs_copy = bool_constant< - !std::is_same()[typename Vector::size_type()]), typename Vector::value_type &>::value>; +template using vector_needs_copy = negation< + std::is_same()[typename Vector::size_type()]), typename Vector::value_type &>>; // The usual case: access and iterate by reference template diff --git a/tests/test_stl_binders.cpp b/tests/test_stl_binders.cpp index b9b56c15d8..ce0b33257d 100644 --- a/tests/test_stl_binders.cpp +++ b/tests/test_stl_binders.cpp @@ -14,6 +14,11 @@ #include #include +#ifdef _MSC_VER +// We get some really long type names here which causes MSVC to emit warnings +# pragma warning(disable: 4503) // warning C4503: decorated name length exceeded, name was truncated +#endif + class El { public: El() = delete;