diff --git a/include/pybind11/common.h b/include/pybind11/common.h index f1b023c91..bf5782041 100644 --- a/include/pybind11/common.h +++ b/include/pybind11/common.h @@ -390,6 +390,21 @@ template class Predicate, class Default, class... T> using firs template struct deferred_type { using type = T; }; template using deferred_t = typename deferred_type::type; +template class Base> +struct is_template_base_of_impl { + template static std::true_type check(Base *); + static std::false_type check(...); +}; + +/// Check if a template is the base of a type. For example: +/// `is_template_base_of` is true if `struct T : Base {}` where U can be anything +template class Base, typename T> +#if !defined(_MSC_VER) +using is_template_base_of = decltype(is_template_base_of_impl::check((T*)nullptr)); +#else // MSVC2015 has trouble with decltype in template aliases +struct is_template_base_of : decltype(is_template_base_of_impl::check((T*)nullptr)) { }; +#endif + /// Ignore that a variable is unused in compiler warnings inline void ignore_unused(const int *) { } diff --git a/include/pybind11/eigen.h b/include/pybind11/eigen.h index c4384ca7a..d8bf41cd0 100644 --- a/include/pybind11/eigen.h +++ b/include/pybind11/eigen.h @@ -34,47 +34,18 @@ NAMESPACE_BEGIN(pybind11) NAMESPACE_BEGIN(detail) -template class is_eigen_dense { -private: - template static std::true_type test(const Eigen::DenseBase &); - static std::false_type test(...); -public: - static constexpr bool value = decltype(test(std::declval()))::value; -}; - -// Eigen::Ref satisfies is_eigen_dense, but isn't constructible, so it needs a special -// type_caster to handle argument copying/forwarding. -template class is_eigen_ref { -private: - template static enable_if_t< - std::is_same::type, Eigen::Ref>::value, - Derived> test(const Eigen::Ref &); - static void test(...); -public: - typedef decltype(test(std::declval())) Derived; - static constexpr bool value = !std::is_void::value; -}; - -template class is_eigen_sparse { -private: - template static std::true_type test(const Eigen::SparseMatrixBase &); - static std::false_type test(...); -public: - static constexpr bool value = decltype(test(std::declval()))::value; -}; +template using is_eigen_dense = is_template_base_of; +template using is_eigen_sparse = is_template_base_of; +template using is_eigen_ref = is_template_base_of; // Test for objects inheriting from EigenBase that aren't captured by the above. This // 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 class is_eigen_base { -private: - template static std::true_type test(const Eigen::EigenBase &); - static std::false_type test(...); -public: - static constexpr bool value = !is_eigen_dense::value && !is_eigen_sparse::value && - decltype(test(std::declval()))::value; -}; +template using is_eigen_base = bool_constant< + is_template_base_of::value + && !is_eigen_dense::value && !is_eigen_sparse::value +>; template struct type_caster::value && !is_eigen_ref::value>> { @@ -159,10 +130,13 @@ protected: static PYBIND11_DESCR cols() { return _(); } }; -template -struct type_caster::value && is_eigen_ref::value>> { +// Eigen::Ref satisfies is_eigen_dense, but isn't constructable, so it needs a special +// type_caster to handle argument copying/forwarding. +template +struct type_caster> { protected: - using Derived = typename std::remove_const::Derived>::type; + using Type = Eigen::Ref; + using Derived = typename std::remove_const::type; using DerivedCaster = type_caster; DerivedCaster derived_caster; std::unique_ptr value;