From d3daeec72e3bba6e0ea6c50444bfa32c5bac8000 Mon Sep 17 00:00:00 2001 From: Drew Hubley Date: Sun, 7 Jun 2026 12:25:24 +0000 Subject: [PATCH 1/5] first stage of eliminating sfinae --- include/xtensor/core/xassign.hpp | 12 +- include/xtensor/core/xeval.hpp | 6 +- include/xtensor/core/xexpression.hpp | 33 +- include/xtensor/core/xfunction.hpp | 4 +- include/xtensor/core/xiterable.hpp | 2 +- include/xtensor/core/xmath.hpp | 4 +- include/xtensor/core/xsemantic.hpp | 2 +- include/xtensor/core/xshape.hpp | 2 +- include/xtensor/misc/xmanipulation.hpp | 2 +- include/xtensor/utils/xutils.hpp | 302 +++++++++---------- include/xtensor/views/xdynamic_view.hpp | 4 +- include/xtensor/views/xfunctor_view.hpp | 24 +- include/xtensor/views/xrepeat.hpp | 6 +- include/xtensor/views/xstrided_view_base.hpp | 7 +- include/xtensor/views/xview.hpp | 26 +- test/test_sfinae.cpp | 37 +-- test/test_xeval.cpp | 2 +- test/test_xutils.cpp | 55 ++-- 18 files changed, 240 insertions(+), 290 deletions(-) diff --git a/include/xtensor/core/xassign.hpp b/include/xtensor/core/xassign.hpp index 904113814..b9439e89a 100644 --- a/include/xtensor/core/xassign.hpp +++ b/include/xtensor/core/xassign.hpp @@ -214,7 +214,7 @@ namespace xt template inline void assign_xexpression(xexpression& e1, const xexpression& e2) { - if constexpr (has_assign_to::value) + if constexpr (has_assign_to()) { e2.derived_cast().assign_to(e1); } @@ -267,14 +267,14 @@ namespace xt template inline auto is_linear_assign(const E1& e1, const E2& e2) - -> std::enable_if_t::value, bool> + -> std::enable_if_t(), bool> { return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout()) || (e1.is_contiguous() && e2.has_linear_assign(e1.strides())); } template - inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t::value, bool> + inline auto is_linear_assign(const E1&, const E2&) -> std::enable_if_t(), bool> { return false; } @@ -304,7 +304,7 @@ namespace xt return std::is_reference::value; } - static constexpr bool value = has_strides::value + static constexpr bool value = has_strides() && has_step_leading::value && stepper_deref(); }; @@ -1002,13 +1002,13 @@ namespace xt const strides_type& m_strides; }; - template ::value || !possible, bool> = true> + template () || !possible, bool> = true> loop_sizes_t get_loop_sizes(const E1& e1, const E2&) { return {false, true, 1, e1.size(), e1.dimension(), e1.dimension()}; } - template ::value && possible, bool> = true> + template () && possible, bool> = true> loop_sizes_t get_loop_sizes(const E1& e1, const E2& e2) { using shape_value_type = typename E1::shape_type::value_type; diff --git a/include/xtensor/core/xeval.hpp b/include/xtensor/core/xeval.hpp index 5ccbc1db9..a863662c7 100644 --- a/include/xtensor/core/xeval.hpp +++ b/include/xtensor/core/xeval.hpp @@ -147,7 +147,7 @@ namespace xt */ template inline auto as_strided(E&& e) - -> std::enable_if_t>::value && detail::has_same_layout(), E&&> + -> std::enable_if_t>() && detail::has_same_layout(), E&&> { return std::forward(e); } @@ -155,7 +155,7 @@ namespace xt /// @cond DOXYGEN_INCLUDE_SFINAE template inline auto as_strided(E&& e) -> std::enable_if_t< - (!(has_data_interface>::value && detail::has_same_layout())) + (!(has_data_interface>() && detail::has_same_layout())) && detail::has_fixed_dims(), detail::as_xtensor_container_t> { @@ -164,7 +164,7 @@ namespace xt template inline auto as_strided(E&& e) -> std::enable_if_t< - (!(has_data_interface>::value && detail::has_same_layout())) + (!(has_data_interface>() && detail::has_same_layout())) && (!detail::has_fixed_dims()), detail::as_xarray_container_t> { diff --git a/include/xtensor/core/xexpression.hpp b/include/xtensor/core/xexpression.hpp index 855c69706..75f4234d8 100644 --- a/include/xtensor/core/xexpression.hpp +++ b/include/xtensor/core/xexpression.hpp @@ -525,15 +525,16 @@ namespace xt using inner_shape_type = typename E::inner_shape_type; using shape_type = typename E::shape_type; - using strides_type = xtl::mpl:: - eval_if_t, detail::expr_strides_type, get_strides_type>; - using backstrides_type = xtl::mpl:: - eval_if_t, detail::expr_backstrides_type, get_strides_type>; - using inner_strides_type = xtl::mpl:: - eval_if_t, detail::expr_inner_strides_type, get_strides_type>; - using inner_backstrides_type = xtl::mpl:: - eval_if_t, detail::expr_inner_backstrides_type, get_strides_type>; - using storage_type = xtl::mpl::eval_if_t, detail::expr_storage_type, make_invalid_type<>>; + using strides_type = typename std:: + conditional_t(), detail::expr_strides_type, get_strides_type>::type; + using backstrides_type = typename std:: + conditional_t(), detail::expr_backstrides_type, get_strides_type>::type; + using inner_strides_type = typename std:: + conditional_t(), detail::expr_inner_strides_type, get_strides_type>::type; + using inner_backstrides_type = typename std:: + conditional_t(), detail::expr_inner_backstrides_type, get_strides_type>::type; + using storage_type = typename std:: + conditional_t(), detail::expr_storage_type, make_invalid_type<>>::type; using stepper = typename E::stepper; using const_stepper = typename E::const_stepper; @@ -638,43 +639,43 @@ namespace xt } template - std::enable_if_t::value, const inner_strides_type&> strides() const + std::enable_if_t(), const inner_strides_type&> strides() const { return m_ptr->strides(); } template - std::enable_if_t::value, const inner_strides_type&> backstrides() const + std::enable_if_t(), const inner_strides_type&> backstrides() const { return m_ptr->backstrides(); } template - std::enable_if_t::value, pointer> data() noexcept + std::enable_if_t(), pointer> data() noexcept { return m_ptr->data(); } template - std::enable_if_t::value, pointer> data() const noexcept + std::enable_if_t(), pointer> data() const noexcept { return m_ptr->data(); } template - std::enable_if_t::value, size_type> data_offset() const noexcept + std::enable_if_t(), size_type> data_offset() const noexcept { return m_ptr->data_offset(); } template - std::enable_if_t::value, typename T::storage_type&> storage() noexcept + std::enable_if_t(), typename T::storage_type&> storage() noexcept { return m_ptr->storage(); } template - std::enable_if_t::value, const typename T::storage_type&> storage() const noexcept + std::enable_if_t(), const typename T::storage_type&> storage() const noexcept { return m_ptr->storage(); } diff --git a/include/xtensor/core/xfunction.hpp b/include/xtensor/core/xfunction.hpp index 6459e998d..929f9dc77 100644 --- a/include/xtensor/core/xfunction.hpp +++ b/include/xtensor/core/xfunction.hpp @@ -133,7 +133,7 @@ namespace xt struct xcontainer_inner_types> { // Added indirection for MSVC 2017 bug with the operator value_type() - using func_return_type = typename meta_identity< + using func_return_type = typename std::type_identity< decltype(std::declval()(std::declval>>()...))>::type; using value_type = std::decay_t; using reference = func_return_type; @@ -156,7 +156,7 @@ namespace xt template struct overlapping_memory_checker_traits< E, - std::enable_if_t::value && is_specialization_of::value>> + std::enable_if_t() && is_specialization_of::value>> { template = 0> static bool check_tuple(const std::tuple&, const memory_range&) diff --git a/include/xtensor/core/xiterable.hpp b/include/xtensor/core/xiterable.hpp index 14d386207..1abdc1220 100644 --- a/include/xtensor/core/xiterable.hpp +++ b/include/xtensor/core/xiterable.hpp @@ -293,7 +293,7 @@ namespace xt }; template - using linear_iterator_traits = linear_iterator_traits_impl::value>; + using linear_iterator_traits = linear_iterator_traits_impl()>; } /** diff --git a/include/xtensor/core/xmath.hpp b/include/xtensor/core/xmath.hpp index 827e84219..16fe8bcc9 100644 --- a/include/xtensor/core/xmath.hpp +++ b/include/xtensor/core/xmath.hpp @@ -350,13 +350,13 @@ namespace xt namespace detail { template - std::enable_if_t::value, R> fill_init(T init) + std::enable_if_t(), R> fill_init(T init) { return R(init); } template - std::enable_if_t::value, R> fill_init(T init) + std::enable_if_t(), R> fill_init(T init) { R result; std::fill(std::begin(result), std::end(result), init); diff --git a/include/xtensor/core/xsemantic.hpp b/include/xtensor/core/xsemantic.hpp index bafad4aca..8a7bca37e 100644 --- a/include/xtensor/core/xsemantic.hpp +++ b/include/xtensor/core/xsemantic.hpp @@ -224,7 +224,7 @@ namespace xt template struct overlapping_memory_checker_traits< E, - std::enable_if_t::value && is_crtp_base_of::value>> + std::enable_if_t() && is_crtp_base_of::value>> { static bool check_overlap(const E& expr, const memory_range& dst_range) { diff --git a/include/xtensor/core/xshape.hpp b/include/xtensor/core/xshape.hpp index 6988e69f3..e395d6157 100644 --- a/include/xtensor/core/xshape.hpp +++ b/include/xtensor/core/xshape.hpp @@ -138,7 +138,7 @@ namespace xt * @param shape the shape to test * @return bool */ - template ::value>> + template ()>> inline bool has_shape(const E& e, const S& shape) { return e.shape().size() == shape.size() diff --git a/include/xtensor/misc/xmanipulation.hpp b/include/xtensor/misc/xmanipulation.hpp index e20095f3e..9272f4c7c 100644 --- a/include/xtensor/misc/xmanipulation.hpp +++ b/include/xtensor/misc/xmanipulation.hpp @@ -214,7 +214,7 @@ namespace xt template inline void compute_transposed_strides(E&& e, const S& shape, X& strides) { - if constexpr (has_data_interface>::value) + if constexpr (has_data_interface>()) { std::copy(e.strides().crbegin(), e.strides().crend(), strides.begin()); } diff --git a/include/xtensor/utils/xutils.hpp b/include/xtensor/utils/xutils.hpp index e93d8e688..4f8248fdf 100644 --- a/include/xtensor/utils/xutils.hpp +++ b/include/xtensor/utils/xutils.hpp @@ -101,16 +101,6 @@ namespace xt template using disable_integral_t = std::enable_if_t::value, R>; - /******************************** - * meta identity implementation * - ********************************/ - - template - struct meta_identity - { - using type = T; - }; - /*************************************** * is_specialization_of implementation * ***************************************/ @@ -370,14 +360,16 @@ namespace xt res[i] = normalize_axis(expr.dimension(), axes[i]); } - XTENSOR_ASSERT(std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return res; } @@ -389,14 +381,16 @@ namespace xt normalize_axis(E& expr, C&& axes) { static_cast(expr); - XTENSOR_ASSERT(std::all_of( - axes.begin(), - axes.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + axes.begin(), + axes.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return std::forward(axes); } @@ -417,14 +411,16 @@ namespace xt } ); - XTENSOR_ASSERT(std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return res; } @@ -439,14 +435,16 @@ namespace xt R res; xt::resize_container(res, std::size(axes)); std::copy(std::begin(axes), std::end(axes), std::begin(res)); - XTENSOR_ASSERT(std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return res; } @@ -456,14 +454,16 @@ namespace xt R&&> { static_cast(expr); - XTENSOR_ASSERT(std::all_of( - std::begin(axes), - std::end(axes), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + std::begin(axes), + std::end(axes), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return std::move(axes); } @@ -471,20 +471,21 @@ namespace xt * get_value_type * ******************/ - template > - struct get_value_type - { - using type = T; - }; - template - struct get_value_type> + constexpr auto get_value_type() { - using type = typename T::value_type; - }; + if constexpr (requires { typename T::value_type; }) + { + return std::type_identity{}; + } + else + { + return std::type_identity{}; + } + } template - using get_value_type_t = typename get_value_type::type; + using get_value_type_t = typename decltype(get_value_type())::type; /********************** * get implementation * @@ -533,81 +534,72 @@ namespace xt * has_storage_type implementation * ***********************************/ - template - struct has_storage_type : std::false_type - { - }; - template struct xcontainer_inner_types; template - struct has_storage_type::storage_type>> - : std::negation< - std::is_same::storage_type>::type, invalid_type>> - { + concept has_storage_type_concept = requires { + typename xcontainer_inner_types::storage_type; + requires !std::is_same_v< + typename std::remove_cv::storage_type>::type, + invalid_type>; }; + template + constexpr bool has_storage_type() + { + return has_storage_type_concept; + } + /************************************* * has_data_interface implementation * *************************************/ - template - struct has_data_interface : std::false_type - { - }; - template - struct has_data_interface().data())>> : std::true_type - { - }; + concept has_data_interface_concept = requires { std::declval().data(); }; template - concept has_data_interface_concept = has_data_interface::value; - - template - struct has_strides : std::false_type + constexpr bool has_data_interface() { - }; + return has_data_interface_concept; + } template - struct has_strides().strides())>> : std::true_type - { - }; + concept has_strides_concept = requires { std::declval().strides(); }; - template - struct has_iterator_interface : std::false_type + template + constexpr bool has_strides() { - }; + return has_strides_concept; + } template - struct has_iterator_interface().begin())>> : std::true_type - { - }; + concept has_iterator_interface_concept = requires { std::declval().begin(); }; template - concept has_iterator_interface_concept = has_iterator_interface::value; + constexpr bool has_iterator_interface() + { + return has_iterator_interface_concept; + } /****************************** * is_iterator implementation * ******************************/ - template - struct is_iterator : std::false_type - { + template + concept iterator_concept = requires { + *std::declval(); + std::declval() == std::declval(); + std::declval() != std::declval(); + ++(*std::declval()); + (*std::declval())++; }; template - struct is_iterator< - E, - void_t< - decltype(*std::declval(), std::declval() == std::declval(), std::declval() != std::declval(), ++(*std::declval()), (*std::declval())++, std::true_type())>> - : std::true_type + constexpr bool is_iterator() { - }; - - template - concept iterator_concept = is_iterator::value; + return iterator_concept; + } /************************* * conditional type cast * @@ -739,38 +731,35 @@ namespace xt * has_assign_to * *****************/ - template - struct has_assign_to : std::false_type - { - }; + template + concept has_assign_to_concept = requires { std::declval().assign_to(std::declval()); }; template - struct has_assign_to().assign_to(std::declval()))>> - : std::true_type + constexpr bool has_assign_to() { - }; + return has_assign_to_concept; + } template - constexpr bool has_assign_to_v = has_assign_to::value; + constexpr bool has_assign_to_v = has_assign_to_concept; /************************************* * overlapping_memory_checker_traits * *************************************/ - template - struct has_memory_address : std::false_type - { - }; + template + concept has_memory_address_concept = requires { std::addressof(*std::declval().begin()); }; template - struct has_memory_address().begin()))>> : std::true_type + constexpr bool has_memory_address() { - }; + return has_memory_address_concept; + } template - concept with_memory_address_concept = has_memory_address>::value; + concept with_memory_address_concept = has_memory_address_concept>; template - concept without_memory_address_concept = !has_memory_address>::value; + concept without_memory_address_concept = !has_memory_address_concept>; struct memory_range { @@ -814,7 +803,7 @@ namespace xt }; template - struct overlapping_memory_checker_traits::value>> + struct overlapping_memory_checker_traits()>> { static bool check_overlap(const E& expr, const memory_range& dst_range) { @@ -864,23 +853,23 @@ namespace xt }; template - struct overlapping_memory_checker::value>> + struct overlapping_memory_checker()>> : overlapping_memory_checker_base { explicit overlapping_memory_checker(const Dst& aDst) : overlapping_memory_checker_base( - [&]() - { - if (aDst.size() == 0) - { - return memory_range(); - } - else - { - return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin())); - } - }() - ) + [&]() + { + if (aDst.size() == 0) + { + return memory_range(); + } + else + { + return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin())); + } + }() + ) { } }; @@ -976,44 +965,33 @@ namespace xt * get_rank * ************/ - template - struct get_rank - { - static constexpr std::size_t value = SIZE_MAX; + // Define the requirement + template + concept HasRank = requires { + T::rank; // Checks if T::rank exists as a type nested member }; template - struct get_rank + constexpr std::size_t has_rank() { - static constexpr std::size_t value = E::rank; - }; - - /****************** - * has_fixed_rank * - ******************/ + return HasRank; + } template - struct has_fixed_rank + constexpr std::size_t get_rank() { - using type = std::integral_constant>::value != SIZE_MAX>; - }; + if constexpr (HasRank>) + { + return std::decay_t::rank; + } + return SIZE_MAX; + } template - using has_fixed_rank_t = typename has_fixed_rank>::type; - - /************ - * has_rank * - ************/ - - template - struct has_rank + constexpr std::size_t has_fixed_rank() { - using type = std::integral_constant>::value == N>; - }; - - template - using has_rank_t = typename has_rank, N>::type; - + return get_rank() != SIZE_MAX; + } } #endif diff --git a/include/xtensor/views/xdynamic_view.hpp b/include/xtensor/views/xdynamic_view.hpp index 5ab298f23..c100d2cae 100644 --- a/include/xtensor/views/xdynamic_view.hpp +++ b/include/xtensor/views/xdynamic_view.hpp @@ -50,9 +50,9 @@ namespace xt #if defined(__GNUC__) && !defined(__clang__) && __GNUC__ == 8 static constexpr auto - random_instantiation_var_for_gcc8_data_iface = has_data_interface>::value; + random_instantiation_var_for_gcc8_data_iface = has_data_interface>(); static constexpr auto - random_instantiation_var_for_gcc8_has_strides = has_strides>::value; + random_instantiation_var_for_gcc8_has_strides = has_strides>(); #endif // TODO: implement efficient stepper specific to the dynamic_view diff --git a/include/xtensor/views/xfunctor_view.hpp b/include/xtensor/views/xfunctor_view.hpp index 1c76a91b5..8325d07e5 100644 --- a/include/xtensor/views/xfunctor_view.hpp +++ b/include/xtensor/views/xfunctor_view.hpp @@ -93,24 +93,24 @@ namespace xt using difference_type = typename xexpression_type::difference_type; using shape_type = typename xexpression_type::shape_type; - using strides_type = xtl::mpl::eval_if_t< - has_strides, + using strides_type = typename std::conditional_t< + has_strides(), detail::expr_strides_type, - get_strides_type>; - using backstrides_type = xtl::mpl::eval_if_t< - has_strides, + get_strides_type>::type; + using backstrides_type = typename std::conditional_t< + has_strides(), detail::expr_backstrides_type, - get_strides_type>; + get_strides_type>::type; using inner_shape_type = typename xexpression_type::inner_shape_type; - using inner_strides_type = xtl::mpl::eval_if_t< - has_strides, + using inner_strides_type = typename std::conditional_t< + has_strides(), detail::expr_inner_strides_type, - get_strides_type>; - using inner_backstrides_type = xtl::mpl::eval_if_t< - has_strides, + get_strides_type>::type; + using inner_backstrides_type = typename std::conditional_t< + has_strides(), detail::expr_inner_backstrides_type, - get_strides_type>; + get_strides_type>::type; using bool_load_type = xt::bool_load_type; diff --git a/include/xtensor/views/xrepeat.hpp b/include/xtensor/views/xrepeat.hpp index 0c119c9af..c43873c6c 100644 --- a/include/xtensor/views/xrepeat.hpp +++ b/include/xtensor/views/xrepeat.hpp @@ -64,10 +64,10 @@ namespace xt static constexpr bool is_const = std::is_const>::value; - using extract_storage_type = xtl::mpl::eval_if_t< - has_data_interface, + using extract_storage_type = typename std::conditional_t< + has_data_interface(), detail::expr_storage_type, - make_invalid_type<>>; + make_invalid_type<>>::type; using storage_type = std::conditional_t; }; diff --git a/include/xtensor/views/xstrided_view_base.hpp b/include/xtensor/views/xstrided_view_base.hpp index 28f233d87..6f53fc988 100644 --- a/include/xtensor/views/xstrided_view_base.hpp +++ b/include/xtensor/views/xstrided_view_base.hpp @@ -87,7 +87,8 @@ namespace xt template struct provides_data_interface - : std::conjunction>, std::negation>> + : std::bool_constant< + has_data_interface>() && !is_flat_expression_adaptor::value> { }; } @@ -278,7 +279,7 @@ namespace xt template using flat_storage_getter = std::conditional_t< - has_data_interface>::value, + has_data_interface>(), inner_storage_getter, flat_adaptor_getter>; @@ -654,7 +655,7 @@ namespace xt template inline bool xstrided_view_base::has_linear_assign(const O& str) const noexcept { - return has_data_interface::value && str.size() == strides().size() + return has_data_interface() && str.size() == strides().size() && std::equal(str.cbegin(), str.cend(), strides().begin()); } diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index 025df0ae4..504b66e3d 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -155,7 +155,7 @@ namespace xt struct is_strided_view : std::integral_constant< bool, - std::conjunction, is_strided_slice_impl>...>::value> + has_data_interface() && (is_strided_slice_impl>::value && ...)> { }; @@ -228,7 +228,7 @@ namespace xt struct is_contiguous_view : std::integral_constant< bool, - has_data_interface::value + has_data_interface() && !( E::static_layout == layout_type::column_major && static_cast(static_dimension::value) != sizeof...(S) @@ -309,10 +309,10 @@ namespace xt static constexpr bool is_const = std::is_const>::value; - using extract_storage_type = xtl::mpl::eval_if_t< - has_data_interface, + using extract_storage_type = typename std::conditional_t< + has_data_interface(), detail::expr_storage_type, - make_invalid_type<>>; + make_invalid_type<>>::type; using storage_type = std::conditional_t; }; @@ -397,15 +397,15 @@ namespace xt using inner_shape_type = typename iterable_base::inner_shape_type; using shape_type = typename xview_shape_type::type; - using xexpression_inner_strides_type = xtl::mpl::eval_if_t< - has_strides, + using xexpression_inner_strides_type = typename std::conditional_t< + has_strides(), detail::expr_inner_strides_type, - get_strides_type>; + get_strides_type>::type; - using xexpression_inner_backstrides_type = xtl::mpl::eval_if_t< - has_strides, + using xexpression_inner_backstrides_type = typename std::conditional_t< + has_strides(), detail::expr_inner_backstrides_type, - get_strides_type>; + get_strides_type>::type; using storage_type = typename inner_types::storage_type; @@ -437,11 +437,11 @@ namespace xt using const_stepper = typename iterable_base::const_stepper; using linear_iterator = std::conditional_t< - has_data_interface::value && is_strided_view, + has_data_interface() && is_strided_view, std::conditional_t, typename iterable_base::linear_iterator>; using const_linear_iterator = std::conditional_t< - has_data_interface::value && is_strided_view, + has_data_interface() && is_strided_view, typename xexpression_type::const_linear_iterator, typename iterable_base::const_linear_iterator>; diff --git a/test/test_sfinae.cpp b/test/test_sfinae.cpp index f79277ac7..d2e8cc8ca 100644 --- a/test/test_sfinae.cpp +++ b/test/test_sfinae.cpp @@ -20,13 +20,13 @@ namespace xt { - template ::value, int> = 0> + template () != 2), int> = 0> inline size_t sfinae_rank_basic_func(E&&) { return 0; } - template ::value, int> = 0> + template () == 2), int> = 0> inline size_t sfinae_rank_basic_func(E&&) { return 2; @@ -50,19 +50,19 @@ namespace xt EXPECT_TRUE(sfinae_rank_basic_func(2ul * c) == 0ul); } - template ::value, int> = 0> + template () == SIZE_MAX), int> = 0> inline size_t sfinae_rank_func(E&&) { return 0; } - template ::value, int> = 0> + template () == 1), int> = 0> inline size_t sfinae_rank_func(E&&) { return 1; } - template ::value, int> = 0> + template () == 2), int> = 0> inline size_t sfinae_rank_func(E&&) { return 2; @@ -86,13 +86,13 @@ namespace xt EXPECT_TRUE(sfinae_rank_func(2ul * c) == 0ul); } - template ::value, int> = 0> + template (), int> = 0> inline bool sfinae_fixed_func(E&&) { return false; } - template ::value, int> = 0> + template (), int> = 0> inline bool sfinae_fixed_func(E&&) { return true; @@ -116,28 +116,17 @@ namespace xt EXPECT_TRUE(sfinae_fixed_func(2ul * c) == false); } - template - struct sfinae_get_rank - { - static const size_t rank = xt::get_rank::value; - - static size_t value() - { - return rank; - } - }; - TEST(sfinae, get_rank) { xt::xtensor A = xt::zeros({2}); xt::xtensor B = xt::zeros({2, 2}); xt::xarray C = xt::zeros({2, 2}); - EXPECT_TRUE(sfinae_get_rank::value() == 1ul); - EXPECT_TRUE(sfinae_get_rank::value() == 2ul); - EXPECT_TRUE(sfinae_get_rank::value() == SIZE_MAX); - EXPECT_TRUE(sfinae_get_rank::value() == SIZE_MAX); - EXPECT_TRUE(sfinae_get_rank::value() == SIZE_MAX); - EXPECT_TRUE(sfinae_get_rank::value() == SIZE_MAX); + static_assert(get_rank() == 1ul); + static_assert(get_rank() == 2ul); + static_assert(get_rank() == SIZE_MAX); + static_assert(get_rank() == SIZE_MAX); + static_assert(get_rank() == SIZE_MAX); + static_assert(get_rank() == SIZE_MAX); } } diff --git a/test/test_xeval.cpp b/test/test_xeval.cpp index f585bfd43..c788b325f 100644 --- a/test/test_xeval.cpp +++ b/test/test_xeval.cpp @@ -61,7 +61,7 @@ namespace xt #define EXPECT_LAYOUT(EXPRESSION, LAYOUT) EXPECT_TRUE((decltype(EXPRESSION)::static_layout == LAYOUT)) -#define HAS_DATA_INTERFACE(EXPRESSION) has_data_interface>::value +#define HAS_DATA_INTERFACE(EXPRESSION) has_data_interface>() #define EXPECT_XARRAY(EXPRESSION) \ EXPECT_TRUE(!detail::is_array::shape_type>::value) diff --git a/test/test_xutils.cpp b/test/test_xutils.cpp index e46a883c8..4fbf476a3 100644 --- a/test/test_xutils.cpp +++ b/test/test_xutils.cpp @@ -124,14 +124,10 @@ namespace xt TEST(utils, has_data_interface) { - bool b = has_data_interface>::value; - EXPECT_TRUE(b); - b = has_data_interface>::value; - EXPECT_TRUE(b); - b = has_data_interface>::value; - EXPECT_TRUE(b); - b = has_data_interface>>::value; - EXPECT_TRUE(b); + static_assert(has_data_interface_concept>); + static_assert(has_data_interface_concept>); + static_assert(has_data_interface_concept>); + static_assert(has_data_interface_concept>>); xarray a = xarray::from_shape({3, 4, 5}); auto f = a + a - 23; @@ -139,39 +135,27 @@ namespace xt auto vv2 = strided_view(v2, {all(), 2}); auto v3 = strided_view(f, {all(), 2}); - b = has_data_interface::value; - EXPECT_TRUE(b); - b = has_data_interface::value; - EXPECT_TRUE(b); - b = has_data_interface::value; - EXPECT_FALSE(b); + static_assert(has_data_interface_concept); + static_assert(has_data_interface_concept); + static_assert(!has_data_interface_concept); } TEST(utils, has_storage_type) { - bool b = has_storage_type>::value; - EXPECT_TRUE(b); + static_assert(has_storage_type>()); xarray x, y; - b = has_storage_type::value; - EXPECT_FALSE(b); - - b = has_storage_type::value; - EXPECT_TRUE(b); - b = has_storage_type::value; - EXPECT_FALSE(b); + static_assert(!has_storage_type()); + static_assert(has_storage_type()); + static_assert(!has_storage_type()); } TEST(utils, has_strides) { - bool b = has_strides>::value; - EXPECT_TRUE(b); - b = has_strides>::value; - EXPECT_TRUE(b); - b = has_strides>::value; - EXPECT_TRUE(b); - b = has_strides>>::value; - EXPECT_TRUE(b); + static_assert(has_strides>()); + static_assert(has_strides>()); + static_assert(has_strides>()); + static_assert(has_strides>>()); xarray a = xarray::from_shape({3, 4, 5}); auto f = a + a - 23; @@ -179,15 +163,12 @@ namespace xt auto vv2 = strided_view(v2, {all(), 2}); auto v3 = strided_view(f, {all(), 2}); - b = has_strides::value; - EXPECT_TRUE(b); - b = has_strides::value; - EXPECT_TRUE(b); + static_assert(has_strides()); + static_assert(has_strides()); #ifndef _MSC_VER // TODO fix this test for MSVC 2015! - b = has_strides::value; - EXPECT_TRUE(b); + static_assert(has_strides()); #endif } From 31f1f59ca59cfe1a1d0a6055ab7a6c28afeb85d1 Mon Sep 17 00:00:00 2001 From: Drew Hubley Date: Sun, 7 Jun 2026 12:35:42 +0000 Subject: [PATCH 2/5] Formatting --- include/xtensor/core/xassign.hpp | 7 +- include/xtensor/core/xeval.hpp | 3 +- include/xtensor/utils/xutils.hpp | 118 +++++++++---------- include/xtensor/views/xstrided_view_base.hpp | 3 +- include/xtensor/views/xview.hpp | 4 +- 5 files changed, 59 insertions(+), 76 deletions(-) diff --git a/include/xtensor/core/xassign.hpp b/include/xtensor/core/xassign.hpp index b9439e89a..d3339cf5f 100644 --- a/include/xtensor/core/xassign.hpp +++ b/include/xtensor/core/xassign.hpp @@ -266,8 +266,7 @@ namespace xt } template - inline auto is_linear_assign(const E1& e1, const E2& e2) - -> std::enable_if_t(), bool> + inline auto is_linear_assign(const E1& e1, const E2& e2) -> std::enable_if_t(), bool> { return (E1::contiguous_layout && E2::contiguous_layout && linear_static_layout()) || (e1.is_contiguous() && e2.has_linear_assign(e1.strides())); @@ -304,8 +303,8 @@ namespace xt return std::is_reference::value; } - static constexpr bool value = has_strides() - && has_step_leading::value && stepper_deref(); + static constexpr bool value = has_strides() && has_step_leading::value + && stepper_deref(); }; template diff --git a/include/xtensor/core/xeval.hpp b/include/xtensor/core/xeval.hpp index a863662c7..f54987635 100644 --- a/include/xtensor/core/xeval.hpp +++ b/include/xtensor/core/xeval.hpp @@ -155,8 +155,7 @@ namespace xt /// @cond DOXYGEN_INCLUDE_SFINAE template inline auto as_strided(E&& e) -> std::enable_if_t< - (!(has_data_interface>() && detail::has_same_layout())) - && detail::has_fixed_dims(), + (!(has_data_interface>() && detail::has_same_layout())) && detail::has_fixed_dims(), detail::as_xtensor_container_t> { return e; diff --git a/include/xtensor/utils/xutils.hpp b/include/xtensor/utils/xutils.hpp index 4f8248fdf..c54eeebd8 100644 --- a/include/xtensor/utils/xutils.hpp +++ b/include/xtensor/utils/xutils.hpp @@ -360,16 +360,14 @@ namespace xt res[i] = normalize_axis(expr.dimension(), axes[i]); } - XTENSOR_ASSERT( - std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - ) - ); + XTENSOR_ASSERT(std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + )); return res; } @@ -381,16 +379,14 @@ namespace xt normalize_axis(E& expr, C&& axes) { static_cast(expr); - XTENSOR_ASSERT( - std::all_of( - axes.begin(), - axes.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - ) - ); + XTENSOR_ASSERT(std::all_of( + axes.begin(), + axes.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + )); return std::forward(axes); } @@ -411,16 +407,14 @@ namespace xt } ); - XTENSOR_ASSERT( - std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - ) - ); + XTENSOR_ASSERT(std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + )); return res; } @@ -435,16 +429,14 @@ namespace xt R res; xt::resize_container(res, std::size(axes)); std::copy(std::begin(axes), std::end(axes), std::begin(res)); - XTENSOR_ASSERT( - std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - ) - ); + XTENSOR_ASSERT(std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + )); return res; } @@ -454,16 +446,14 @@ namespace xt R&&> { static_cast(expr); - XTENSOR_ASSERT( - std::all_of( - std::begin(axes), - std::end(axes), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - ) - ); + XTENSOR_ASSERT(std::all_of( + std::begin(axes), + std::end(axes), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + )); return std::move(axes); } @@ -540,9 +530,7 @@ namespace xt template concept has_storage_type_concept = requires { typename xcontainer_inner_types::storage_type; - requires !std::is_same_v< - typename std::remove_cv::storage_type>::type, - invalid_type>; + requires !std::is_same_v::storage_type>::type, invalid_type>; }; template @@ -858,18 +846,18 @@ namespace xt { explicit overlapping_memory_checker(const Dst& aDst) : overlapping_memory_checker_base( - [&]() - { - if (aDst.size() == 0) - { - return memory_range(); - } - else - { - return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin())); - } - }() - ) + [&]() + { + if (aDst.size() == 0) + { + return memory_range(); + } + else + { + return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin())); + } + }() + ) { } }; diff --git a/include/xtensor/views/xstrided_view_base.hpp b/include/xtensor/views/xstrided_view_base.hpp index 6f53fc988..0591f9eaa 100644 --- a/include/xtensor/views/xstrided_view_base.hpp +++ b/include/xtensor/views/xstrided_view_base.hpp @@ -87,8 +87,7 @@ namespace xt template struct provides_data_interface - : std::bool_constant< - has_data_interface>() && !is_flat_expression_adaptor::value> + : std::bool_constant>() && !is_flat_expression_adaptor::value> { }; } diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index 504b66e3d..f52f47469 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -153,9 +153,7 @@ namespace xt // If we have no discontiguous slices, we can calculate strides for this view. template struct is_strided_view - : std::integral_constant< - bool, - has_data_interface() && (is_strided_slice_impl>::value && ...)> + : std::integral_constant() && (is_strided_slice_impl>::value && ...)> { }; From c66d4a45eaf62b83fc96fa69dd941547b8b2f472 Mon Sep 17 00:00:00 2001 From: Drew Hubley Date: Sun, 7 Jun 2026 13:00:12 +0000 Subject: [PATCH 3/5] Elminated some sfinae in xviews --- include/xtensor/views/xview.hpp | 78 +++++++++++++++++---------------- 1 file changed, 40 insertions(+), 38 deletions(-) diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index f52f47469..ffad1f513 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -129,31 +129,32 @@ namespace xt template struct is_xscalar_impl> { - static constexpr bool value = static_cast(integral_count() - ) == static_dimension::shape_type>::value + static constexpr bool value = static_cast(integral_count()) + == static_dimension::shape_type>::value ? true : false; }; - template - struct is_strided_slice_impl : std::true_type - { - }; + template + inline constexpr bool is_strided_slice_impl = true; + template + inline constexpr bool is_strided_slice_impl> = false; + template + inline constexpr bool is_strided_slice_impl> = false; - template - struct is_strided_slice_impl> : std::false_type - { - }; + template + concept is_strided_slice_concept = is_strided_slice_impl; - template - struct is_strided_slice_impl> : std::false_type + template + constexpr bool is_strided_slice() { - }; + return (is_strided_slice_concept> && ...); + } // If we have no discontiguous slices, we can calculate strides for this view. template struct is_strided_view - : std::integral_constant() && (is_strided_slice_impl>::value && ...)> + : std::integral_constant() && is_strided_slice()> { }; @@ -878,11 +879,11 @@ namespace xt template xview::xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept : xview( - std::integral_constant{}, - std::forward(e), - std::forward(first_slice), - std::forward(slices)... - ) + std::integral_constant{}, + std::forward(e), + std::forward(first_slice), + std::forward(slices)... + ) { } @@ -1265,27 +1266,29 @@ namespace xt */ template template - inline auto xview::strides() const - -> const inner_strides_type& requires(has_data_interface_conceptand strided_view_concept) { - if (!m_strides_computed) - { - compute_strides(std::integral_constant{}); - m_strides_computed = true; - } - return m_strides; + inline auto xview::strides() const -> const inner_strides_type& + requires(has_data_interface_concept and strided_view_concept) + { + if (!m_strides_computed) + { + compute_strides(std::integral_constant{}); + m_strides_computed = true; } + return m_strides; + } template template - inline auto xview::backstrides() const - -> const inner_strides_type& requires(has_data_interface_conceptand strided_view_concept) { - if (!m_strides_computed) - { - compute_strides(std::integral_constant{}); - m_strides_computed = true; - } - return m_backstrides; + inline auto xview::backstrides() const -> const inner_strides_type& + requires(has_data_interface_concept and strided_view_concept) + { + if (!m_strides_computed) + { + compute_strides(std::integral_constant{}); + m_strides_computed = true; } + return m_backstrides; + } /** * Return the pointer to the underlying buffer. @@ -1696,9 +1699,8 @@ namespace xt return xt::value(s, 0); }; - auto s = static_cast( - (std::min)(static_cast(std::distance(first, last)), this->dimension()) - ); + auto s = static_cast((std::min) (static_cast(std::distance(first, last)), + this->dimension())); auto first_copy = last - s; for (size_type i = 0; i != m_e.dimension(); ++i) { From 7e6e3c345e1082444d3e75270a915e4b8a0d93ae Mon Sep 17 00:00:00 2001 From: Drew Hubley Date: Sun, 7 Jun 2026 13:01:13 +0000 Subject: [PATCH 4/5] formatting --- include/xtensor/views/xview.hpp | 53 ++++++++++++++++----------------- 1 file changed, 26 insertions(+), 27 deletions(-) diff --git a/include/xtensor/views/xview.hpp b/include/xtensor/views/xview.hpp index ffad1f513..780836959 100644 --- a/include/xtensor/views/xview.hpp +++ b/include/xtensor/views/xview.hpp @@ -129,8 +129,8 @@ namespace xt template struct is_xscalar_impl> { - static constexpr bool value = static_cast(integral_count()) - == static_dimension::shape_type>::value + static constexpr bool value = static_cast(integral_count() + ) == static_dimension::shape_type>::value ? true : false; }; @@ -879,11 +879,11 @@ namespace xt template xview::xview(CTA&& e, FSL&& first_slice, SL&&... slices) noexcept : xview( - std::integral_constant{}, - std::forward(e), - std::forward(first_slice), - std::forward(slices)... - ) + std::integral_constant{}, + std::forward(e), + std::forward(first_slice), + std::forward(slices)... + ) { } @@ -1266,29 +1266,27 @@ namespace xt */ template template - inline auto xview::strides() const -> const inner_strides_type& - requires(has_data_interface_concept and strided_view_concept) - { - if (!m_strides_computed) - { - compute_strides(std::integral_constant{}); - m_strides_computed = true; + inline auto xview::strides() const + -> const inner_strides_type& requires(has_data_interface_conceptand strided_view_concept) { + if (!m_strides_computed) + { + compute_strides(std::integral_constant{}); + m_strides_computed = true; + } + return m_strides; } - return m_strides; - } template template - inline auto xview::backstrides() const -> const inner_strides_type& - requires(has_data_interface_concept and strided_view_concept) - { - if (!m_strides_computed) - { - compute_strides(std::integral_constant{}); - m_strides_computed = true; + inline auto xview::backstrides() const + -> const inner_strides_type& requires(has_data_interface_conceptand strided_view_concept) { + if (!m_strides_computed) + { + compute_strides(std::integral_constant{}); + m_strides_computed = true; + } + return m_backstrides; } - return m_backstrides; - } /** * Return the pointer to the underlying buffer. @@ -1699,8 +1697,9 @@ namespace xt return xt::value(s, 0); }; - auto s = static_cast((std::min) (static_cast(std::distance(first, last)), - this->dimension())); + auto s = static_cast( + (std::min)(static_cast(std::distance(first, last)), this->dimension()) + ); auto first_copy = last - s; for (size_type i = 0; i != m_e.dimension(); ++i) { From 62d19f4ad840e8eb01733be8a9f05d670805fcb9 Mon Sep 17 00:00:00 2001 From: Drew Hubley Date: Sun, 7 Jun 2026 22:15:45 +0000 Subject: [PATCH 5/5] Updated find strides --- include/xtensor/utils/xutils.hpp | 219 ++++++++++++++++++------------- 1 file changed, 129 insertions(+), 90 deletions(-) diff --git a/include/xtensor/utils/xutils.hpp b/include/xtensor/utils/xutils.hpp index c54eeebd8..ee302bde1 100644 --- a/include/xtensor/utils/xutils.hpp +++ b/include/xtensor/utils/xutils.hpp @@ -360,14 +360,16 @@ namespace xt res[i] = normalize_axis(expr.dimension(), axes[i]); } - XTENSOR_ASSERT(std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return res; } @@ -379,14 +381,16 @@ namespace xt normalize_axis(E& expr, C&& axes) { static_cast(expr); - XTENSOR_ASSERT(std::all_of( - axes.begin(), - axes.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + axes.begin(), + axes.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return std::forward(axes); } @@ -407,14 +411,16 @@ namespace xt } ); - XTENSOR_ASSERT(std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return res; } @@ -429,14 +435,16 @@ namespace xt R res; xt::resize_container(res, std::size(axes)); std::copy(std::begin(axes), std::end(axes), std::begin(res)); - XTENSOR_ASSERT(std::all_of( - res.begin(), - res.end(), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + res.begin(), + res.end(), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return res; } @@ -446,14 +454,16 @@ namespace xt R&&> { static_cast(expr); - XTENSOR_ASSERT(std::all_of( - std::begin(axes), - std::end(axes), - [&expr](auto ax_el) - { - return ax_el < expr.dimension(); - } - )); + XTENSOR_ASSERT( + std::all_of( + std::begin(axes), + std::end(axes), + [&expr](auto ax_el) + { + return ax_el < expr.dimension(); + } + ) + ); return std::move(axes); } @@ -729,7 +739,7 @@ namespace xt } template - constexpr bool has_assign_to_v = has_assign_to_concept; + constexpr bool has_assign_to_v = has_assign_to(); /************************************* * overlapping_memory_checker_traits * @@ -846,18 +856,18 @@ namespace xt { explicit overlapping_memory_checker(const Dst& aDst) : overlapping_memory_checker_base( - [&]() - { - if (aDst.size() == 0) - { - return memory_range(); - } - else - { - return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin())); - } - }() - ) + [&]() + { + if (aDst.size() == 0) + { + return memory_range(); + } + else + { + return memory_range(std::addressof(*aDst.begin()), std::addressof(*aDst.rbegin())); + } + }() + ) { } }; @@ -895,59 +905,88 @@ namespace xt }; #endif - /******************** - * get_strides_type * - ********************/ + /*************** + * get_strides * + ***************/ - template - struct get_strides_type - { - using type = typename rebind_container::type; - }; + template + class xbuffer_adaptor; - template - struct get_strides_type> + namespace detail { - // TODO we could compute the strides statically here. - // But we'll need full constexpr support to have a - // homogenous ``compute_strides`` method - using type = std::array; - }; + template + inline constexpr bool is_fixed_shape_v = false; - template - class xbuffer_adaptor; + template + inline constexpr bool is_fixed_shape_v> = true; - template - struct get_strides_type> - { - // In bindings this mapping is called by reshape_view with an inner shape of type - // xbuffer_adaptor. - // Since we cannot create a buffer adaptor holding data, we map it to an std::vector. - using type = std::vector< - typename xbuffer_adaptor::value_type, - typename xbuffer_adaptor::allocator_type>; - }; + template + inline constexpr bool is_xbuffer_adaptor_v = false; + template + inline constexpr bool is_xbuffer_adaptor_v> = true; - template - using get_strides_t = typename get_strides_type::type; + template + concept fixed_shape_type = is_fixed_shape_v; + + template + concept xbuffer_adaptor_type = is_xbuffer_adaptor_v; + } + + template + constexpr auto get_strides() + { + if constexpr (detail::fixed_shape_type) + { + // TODO we could compute the strides statically here. + // But we'll need full constexpr support to have a + // homogenous ``compute_strides`` method + return std::type_identity>{}; + } + else if constexpr (detail::xbuffer_adaptor_type) + { + // In bindings this mapping is called by reshape_view with an inner shape of type + // xbuffer_adaptor. + // Since we cannot create a buffer adaptor holding data, we map it to an std::vector. + return std::type_identity>{}; + } + else + { + return std::type_identity::type>{}; + } + } + + template + using get_strides_t = typename decltype(get_strides())::type; + + // Lazy metafunction wrapper around ``get_strides``. Kept so callers can defer the mapping + // inside ``std::conditional_t::type``, where ``::type`` is only evaluated on the + // selected branch (see xshared_expression in xexpression.hpp). + template + struct get_strides_type + { + using type = get_strides_t; + }; /******************* * inner_reference * *******************/ - template - struct inner_reference + constexpr auto get_inner_reference() { using storage_type = std::decay_t; - using type = std::conditional_t< - std::is_const>::value, - typename storage_type::const_reference, - typename storage_type::reference>; - }; + if constexpr (std::is_const>::value) + { + return std::type_identity{}; + } + else + { + return std::type_identity{}; + } + } template - using inner_reference_t = typename inner_reference::type; + using inner_reference_t = typename decltype(get_inner_reference())::type; /************ * get_rank *