mirror of
https://github.com/pybind/pybind11.git
synced 2024-11-25 14:45:12 +00:00
Change all_of_t/any_of_t to all_of/any_of, add none_of
This replaces the current `all_of_t<Pred, Ts...>` with `all_of<Ts...>`, with previous use of `all_of_t<Pred, Ts...>` becoming `all_of<Pred<Ts>...>` (and similarly for `any_of_t`). It also adds a `none_of<Ts...>`, a shortcut for `negation<any_of<Ts...>>`. This allows `all_of` and `any_of` to be used a bit more flexible, e.g. in cases where several predicates need to be tested for the same type instead of the same predicate for multiple types. This commit replaces the implementation with a more efficient version for non-MSVC. For MSVC, this changes the workaround to use the built-in, recursive std::conjunction/std::disjunction instead. This also removes the `count_t` since `any_of_t` and `all_of_t` were the only things using it. This commit also rearranges some of the future std imports to use actual `std` implementations for C++14/17 features when under the appropriate compiler mode, as we were already doing for a few things (like index_sequence). Most of these aren't saving much (the implementation for enable_if_t, for example, is trivial), but I think it makes the intention of the code instantly clear. It also enables MSVC's native std::index_sequence support.
This commit is contained in:
parent
b11b144603
commit
fa5d05e15d
@ -1003,23 +1003,24 @@ class type_caster<T, enable_if_t<is_pyobject<T>::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 <typename T, typename SFINAE = void> struct move_is_plain_type : std::false_type {};
|
||||
template <typename T> struct move_is_plain_type<T, enable_if_t<
|
||||
!std::is_void<T>::value && !std::is_pointer<T>::value && !std::is_reference<T>::value && !std::is_const<T>::value
|
||||
>> : std::true_type { };
|
||||
template <typename T> using move_is_plain_type = none_of<
|
||||
std::is_void<T>, std::is_pointer<T>, std::is_reference<T>, std::is_const<T>
|
||||
>;
|
||||
template <typename T, typename SFINAE = void> struct move_always : std::false_type {};
|
||||
template <typename T> struct move_always<T, enable_if_t<
|
||||
move_is_plain_type<T>::value &&
|
||||
!std::is_copy_constructible<T>::value && std::is_move_constructible<T>::value &&
|
||||
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
|
||||
>> : std::true_type { };
|
||||
template <typename T> struct move_always<T, enable_if_t<all_of<
|
||||
move_is_plain_type<T>,
|
||||
negation<std::is_copy_constructible<T>>,
|
||||
std::is_move_constructible<T>,
|
||||
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>
|
||||
>::value>> : std::true_type {};
|
||||
template <typename T, typename SFINAE = void> struct move_if_unreferenced : std::false_type {};
|
||||
template <typename T> struct move_if_unreferenced<T, enable_if_t<
|
||||
move_is_plain_type<T>::value &&
|
||||
!move_always<T>::value && std::is_move_constructible<T>::value &&
|
||||
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>::value
|
||||
>> : std::true_type { };
|
||||
template <typename T> using move_never = std::integral_constant<bool, !move_always<T>::value && !move_if_unreferenced<T>::value>;
|
||||
template <typename T> struct move_if_unreferenced<T, enable_if_t<all_of<
|
||||
move_is_plain_type<T>,
|
||||
negation<move_always<T>>,
|
||||
std::is_move_constructible<T>,
|
||||
std::is_same<decltype(std::declval<type_caster<T>>().operator T&()), T&>
|
||||
>::value>> : std::true_type {};
|
||||
template <typename T> using move_never = none_of<move_always<T>, move_if_unreferenced<T>>;
|
||||
|
||||
// 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
|
||||
@ -1079,7 +1080,7 @@ template <typename T> T handle::cast() const { return pybind11::cast<T>(*this);
|
||||
template <> inline void handle::cast() const { return; }
|
||||
|
||||
template <typename T>
|
||||
detail::enable_if_t<detail::move_always<T>::value || detail::move_if_unreferenced<T>::value, T> move(object &&obj) {
|
||||
detail::enable_if_t<!detail::move_never<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 @@ private:
|
||||
|
||||
/// Collect only positional arguments for a Python function call
|
||||
template <return_value_policy policy, typename... Args,
|
||||
typename = enable_if_t<all_of_t<is_positional, Args...>::value>>
|
||||
typename = enable_if_t<all_of<is_positional<Args>...>::value>>
|
||||
simple_collector<policy> collect_arguments(Args &&...args) {
|
||||
return simple_collector<policy>(std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/// Collect all arguments, including keywords and unpacking (only instantiated when needed)
|
||||
template <return_value_policy policy, typename... Args,
|
||||
typename = enable_if_t<!all_of_t<is_positional, Args...>::value>>
|
||||
typename = enable_if_t<!all_of<is_positional<Args>...>::value>>
|
||||
unpacking_collector<policy> collect_arguments(Args &&...args) {
|
||||
// Following argument order rules for generalized unpacking according to PEP 448
|
||||
static_assert(
|
||||
|
@ -356,8 +356,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 <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
|
||||
#endif
|
||||
|
||||
/// Index sequences
|
||||
#if defined(PYBIND11_CPP14) || defined(_MSC_VER)
|
||||
using std::index_sequence;
|
||||
using std::make_index_sequence;
|
||||
#else
|
||||
@ -367,6 +376,29 @@ template<size_t ...S> struct make_index_sequence_impl <0, S...> { typedef index_
|
||||
template<size_t N> using make_index_sequence = typename make_index_sequence_impl<N>::type;
|
||||
#endif
|
||||
|
||||
#if defined(PYBIND11_CPP17) || defined(_MSC_VER)
|
||||
using std::bool_constant;
|
||||
using std::negation;
|
||||
#else
|
||||
template <bool B> using bool_constant = std::integral_constant<bool, B>;
|
||||
template <class T> using negation = bool_constant<!T::value>;
|
||||
#endif
|
||||
|
||||
/// Compile-time all/any/none of that check the ::value of all template types
|
||||
#if !defined(_MSC_VER)
|
||||
template <bool...> struct bools {};
|
||||
template <class... Ts> using all_of = std::is_same<
|
||||
bools<Ts::value..., true>,
|
||||
bools<true, Ts::value...>>;
|
||||
template <class... Ts> using any_of = negation<all_of<negation<Ts>...>>;
|
||||
#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 <class... Ts> using all_of = std::conjunction<Ts...>;
|
||||
template <class... Ts> using any_of = std::disjunction<Ts...>;
|
||||
#endif
|
||||
template <class... Ts> using none_of = negation<any_of<Ts...>>;
|
||||
|
||||
/// Strip the class from a method type
|
||||
template <typename T> struct remove_class { };
|
||||
template <typename C, typename R, typename... A> struct remove_class<R (C::*)(A...)> { typedef R type(A...); };
|
||||
@ -388,35 +420,11 @@ struct void_type { };
|
||||
/// Helper template which holds a list of types
|
||||
template <typename...> struct type_list { };
|
||||
|
||||
/// from __cpp_future__ import (convenient aliases from C++14/17)
|
||||
template <bool B> using bool_constant = std::integral_constant<bool, B>;
|
||||
template <class T> using negation = bool_constant<!T::value>;
|
||||
template <bool B, typename T = void> using enable_if_t = typename std::enable_if<B, T>::type;
|
||||
template <bool B, typename T, typename F> using conditional_t = typename std::conditional<B, T, F>::type;
|
||||
|
||||
/// Compile-time integer sum
|
||||
constexpr size_t constexpr_sum() { return 0; }
|
||||
template <typename T, typename... Ts>
|
||||
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 <template<typename> class Predicate, typename... Ts>
|
||||
using count_t = std::integral_constant<size_t, constexpr_sum(Predicate<Ts>::value...)>;
|
||||
#else
|
||||
// MSVC workaround (2015 Update 3 has issues with some member type aliases and constexpr)
|
||||
template <template<typename> class Predicate, typename... Ts> struct count_t;
|
||||
template <template<typename> class Predicate> struct count_t<Predicate> : std::integral_constant<size_t, 0> {};
|
||||
template <template<typename> class Predicate, class T, class... Ts>
|
||||
struct count_t<Predicate, T, Ts...> : std::integral_constant<size_t, Predicate<T>::value + count_t<Predicate, Ts...>::value> {};
|
||||
#endif
|
||||
|
||||
/// Return true if all/any Ts satify Predicate<T>
|
||||
template <template<typename> class Predicate, typename... Ts>
|
||||
using all_of_t = bool_constant<(count_t<Predicate, Ts...>::value == sizeof...(Ts))>;
|
||||
template <template<typename> class Predicate, typename... Ts>
|
||||
using any_of_t = bool_constant<(count_t<Predicate, Ts...>::value > 0)>;
|
||||
|
||||
// Extracts the first type from the template parameter pack matching the predicate, or Default if none match.
|
||||
template <template<class> class Predicate, class Default, class... Ts> struct first_of;
|
||||
template <template<class> class Predicate, class Default> struct first_of<Predicate, Default> {
|
||||
|
@ -41,9 +41,10 @@ template <typename T> using is_eigen_ref = is_template_base_of<Eigen::RefBase, T
|
||||
// basically covers anything that can be assigned to a dense matrix but that don't have a typical
|
||||
// matrix data layout that can be copied from their .data(). For example, DiagonalMatrix and
|
||||
// SelfAdjointView fall into this category.
|
||||
template <typename T> using is_eigen_base = bool_constant<
|
||||
is_template_base_of<Eigen::EigenBase, T>::value
|
||||
&& !is_eigen_dense<T>::value && !is_eigen_sparse<T>::value
|
||||
template <typename T> using is_eigen_base = all_of<
|
||||
is_template_base_of<Eigen::EigenBase, T>,
|
||||
negation<is_eigen_dense<T>>,
|
||||
negation<is_eigen_sparse<T>>
|
||||
>;
|
||||
|
||||
template<typename Type>
|
||||
|
@ -924,12 +924,9 @@ class class_ : public detail::generic_type {
|
||||
template <typename T> using is_holder = detail::is_holder_type<type_, T>;
|
||||
template <typename T> using is_subtype = detail::bool_constant<std::is_base_of<type_, T>::value && !std::is_same<T, type_>::value>;
|
||||
template <typename T> using is_base = detail::bool_constant<std::is_base_of<T, type_>::value && !std::is_same<T, type_>::value>;
|
||||
template <typename T> using is_valid_class_option =
|
||||
detail::bool_constant<
|
||||
is_holder<T>::value ||
|
||||
is_subtype<T>::value ||
|
||||
is_base<T>::value
|
||||
>;
|
||||
// struct instead of using here to help MSVC:
|
||||
template <typename T> struct is_valid_class_option :
|
||||
detail::any_of<is_holder<T>, is_subtype<T>, is_base<T>> {};
|
||||
|
||||
public:
|
||||
using type = type_;
|
||||
@ -938,7 +935,7 @@ public:
|
||||
using holder_type = detail::first_of_t<is_holder, std::unique_ptr<type>, options...>;
|
||||
using instance_type = detail::instance<type, holder_type>;
|
||||
|
||||
static_assert(detail::all_of_t<is_valid_class_option, options...>::value,
|
||||
static_assert(detail::all_of<is_valid_class_option<options>...>::value,
|
||||
"Unknown/invalid class_ template parameters provided");
|
||||
|
||||
PYBIND11_OBJECT(class_, generic_type, PyType_Check)
|
||||
|
@ -410,12 +410,10 @@ public:
|
||||
template <typename T> using is_keyword = std::is_base_of<arg, T>;
|
||||
template <typename T> using is_s_unpacking = std::is_same<args_proxy, T>; // * unpacking
|
||||
template <typename T> using is_ds_unpacking = std::is_same<kwargs_proxy, T>; // ** unpacking
|
||||
template <typename T> using is_positional = bool_constant<
|
||||
!is_keyword<T>::value && !is_s_unpacking<T>::value && !is_ds_unpacking<T>::value
|
||||
>;
|
||||
template <typename T> using is_keyword_or_ds = bool_constant<
|
||||
is_keyword<T>::value || is_ds_unpacking<T>::value
|
||||
template <typename T> using is_positional = none_of<
|
||||
is_keyword<T>, is_s_unpacking<T>, is_ds_unpacking<T>
|
||||
>;
|
||||
template <typename T> using is_keyword_or_ds = any_of<is_keyword<T>, is_ds_unpacking<T>>;
|
||||
|
||||
// Call argument collector forward declarations
|
||||
template <return_value_policy policy = return_value_policy::automatic_reference>
|
||||
@ -754,7 +752,7 @@ public:
|
||||
if (!m_ptr) pybind11_fail("Could not allocate dict object!");
|
||||
}
|
||||
template <typename... Args,
|
||||
typename = detail::enable_if_t<detail::all_of_t<detail::is_keyword_or_ds, Args...>::value>,
|
||||
typename = detail::enable_if_t<detail::all_of<detail::is_keyword_or_ds<Args>...>::value>,
|
||||
// MSVC workaround: it can't compile an out-of-line definition, so defer the collector
|
||||
typename collector = detail::deferred_t<detail::unpacking_collector<>, Args...>>
|
||||
explicit dict(Args &&...args) : dict(collector(std::forward<Args>(args)...).kwargs()) { }
|
||||
|
@ -253,8 +253,8 @@ void vector_modifiers(enable_if_t<std::is_copy_constructible<typename Vector::va
|
||||
|
||||
// If the type has an operator[] that doesn't return a reference (most notably std::vector<bool>),
|
||||
// we have to access by copying; otherwise we return by reference.
|
||||
template <typename Vector> using vector_needs_copy = bool_constant<
|
||||
!std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>::value>;
|
||||
template <typename Vector> using vector_needs_copy = negation<
|
||||
std::is_same<decltype(std::declval<Vector>()[typename Vector::size_type()]), typename Vector::value_type &>>;
|
||||
|
||||
// The usual case: access and iterate by reference
|
||||
template <typename Vector, typename Class_>
|
||||
|
@ -14,6 +14,11 @@
|
||||
#include <deque>
|
||||
#include <unordered_map>
|
||||
|
||||
#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;
|
||||
|
Loading…
Reference in New Issue
Block a user