Repository: xtensor-stack/xtensor (language: python)

Issue:
Operations xt::real and xt::imag on views do not compile
Hi, I would like to take work on the real/imag parts of a view onto a complex array, but this seems to fail at compile time. Here is a piece of code that fails compilation. 

```
#include <iostream>
#include <complex>
#include <xtensor/xtensor.hpp>
#include <xtensor/xio.hpp>
#include <xtensor/xnorm.hpp>
#include <xtensor/xmath.hpp>
#include <xtensor/xview.hpp>
#include <xtensor/xcomplex.hpp>

using cpx = std::complex<double>;
using std::complex;

template<class T>
xt::xtensor<T, 1> mynorm(xt::xtensor<complex<T>, 2> &a)
{
  return xt::sum(xt::square(xt::abs(a)), {0});
}

int main()
{
  xt::xtensor<cpx, 2> a = {
    { cpx(1, 1), cpx(-1, 1), cpx(-2, -2) },
    { cpx(-1, 0), cpx(0, 1), cpx(2, 2) }
  };

  // This compiles
  std::cout <<  xt::real(a) << std::endl;
  std::cout << xt::imag(a) << std::endl;
  std::cout << xt::conj(a) << std::endl;

  // This compiles
  std::cout << xt::conj(xt::view(a, 0, xt::all())) << std::endl;

  // This does not
  std::cout <<  xt::real(xt::view(a, 0, xt::all())) << std::endl;
  std::cout << xt::imag(xt::view(a, 0, xt::all())) << std::endl;

}
```

The compilation error is the following.
```
> make test_cpx_real
Scanning dependencies of target test_cpx_real
[ 50%] Building CXX object CMakeFiles/test_cpx_real.dir/src/test_cpx_real.cpp.o
In file included from /Users/scheibler/Documents/Research/Projects/Current/Separation/mixiva/test_xtensor/src/test_cpx_real.cpp:3:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xtensor.hpp:19:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcontainer.hpp:23:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xmath.hpp:25:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xaccumulator.hpp:17:
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xexpression.hpp:410:38: error: no type named 'backstrides_type' in
      'xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>, std::__1::allocator<std::__1::complex<double> > >, 2,
      xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned long> >'
            using type = typename E::backstrides_type;
                         ~~~~~~~~~~~~^~~~~~~~~~~~~~~~
/Users/scheibler/anaconda3/envs/mixiva/include/xtl/xmeta_utils.hpp:77:35: note: in instantiation of template class
      'xt::detail::expr_backstrides_type<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
            using type = typename T::type;
                                  ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtl/xmeta_utils.hpp:87:26: note: in instantiation of template class 'xtl::mpl::eval_if_c<true,
      xt::detail::expr_backstrides_type<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >, xt::get_strides_type<std::__1::array<unsigned long, 1> > >' requested here
        struct eval_if : eval_if_c<B::value, T, F>
                         ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtl/xmeta_utils.hpp:92:9: note: in instantiation of template class
      'xtl::mpl::eval_if<xt::has_strides<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> >, void>, xt::detail::expr_backstrides_type<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >, xt::get_strides_type<std::__1::array<unsigned long, 1> > >' requested here
        using eval_if_t = typename eval_if<B, T, F>::type;
        ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xfunctor_view.hpp:94:44: note: in instantiation of template type alias 'eval_if_t'
      requested here
        using backstrides_type = xtl::mpl::eval_if_t<has_strides<xexpression_type>,
                                           ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xfunctor_view.hpp:376:34: note: in instantiation of template class
      'xt::xfunctor_applier_base<xt::xfunctor_view<xt::detail::offset_forwarder<double, 0>,
      xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>, std::__1::allocator<std::__1::complex<double> > >, 2,
      xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned long> > > >' requested here
    class xfunctor_view : public xfunctor_applier_base<xfunctor_view<F, CT>>,
                                 ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcomplex.hpp:46:24: note: in instantiation of template class
      'xt::xfunctor_view<xt::detail::offset_forwarder<double, 0>, xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
                return xoffset_view<xclosure_t<E>, real_type, 0>(std::forward<E>(e));
                       ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcomplex.hpp:79:110: note: in instantiation of function template specialization
      'xt::detail::complex_helper<true>::real<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
                return detail::complex_helper<xtl::is_complex<typename std::decay_t<E>::value_type>::value>::real(std::forward<E>(e));
                                                                                                             ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcomplex.hpp:117:91: note: in instantiation of function template specialization
      'xt::detail::complex_expression_helper<true>::real<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
        return detail::complex_expression_helper<is_xexpression<std::decay_t<E>>::value>::real(std::forward<E>(e));
                                                                                          ^
/Users/scheibler/Documents/Research/Projects/Current/Separation/mixiva/test_xtensor/src/test_cpx_real.cpp:36:21: note: in instantiation of
      function template specialization 'xt::real<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
  std::cout <<  xt::real(xt::view(a, 0, xt::all())) << std::endl;
                    ^
In file included from /Users/scheibler/Documents/Research/Projects/Current/Separation/mixiva/test_xtensor/src/test_cpx_real.cpp:3:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xtensor.hpp:18:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xbuffer_adaptor.hpp:20:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xstorage.hpp:21:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xtensor_simd.hpp:14:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xutils.hpp:25:
In file included from /Users/scheibler/anaconda3/envs/mixiva/include/xtl/xsequence.hpp:19:
/Users/scheibler/anaconda3/envs/mixiva/include/xtl/xmeta_utils.hpp:92:9: error: no type named 'type' in
      'xtl::mpl::eval_if<xt::has_strides<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> >, void>, xt::detail::expr_backstrides_type<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >, xt::get_strides_type<std::__1::array<unsigned long, 1> > >'
        using eval_if_t = typename eval_if<B, T, F>::type;
        ^~~~~
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xfunctor_view.hpp:94:44: note: in instantiation of template type alias 'eval_if_t'
      requested here
        using backstrides_type = xtl::mpl::eval_if_t<has_strides<xexpression_type>,
                                           ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xfunctor_view.hpp:376:34: note: in instantiation of template class
      'xt::xfunctor_applier_base<xt::xfunctor_view<xt::detail::offset_forwarder<double, 8>,
      xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>, std::__1::allocator<std::__1::complex<double> > >, 2,
      xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned long> > > >' requested here
    class xfunctor_view : public xfunctor_applier_base<xfunctor_view<F, CT>>,
                                 ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcomplex.hpp:53:24: note: in instantiation of template class
      'xt::xfunctor_view<xt::detail::offset_forwarder<double, 8>, xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
                return xoffset_view<xclosure_t<E>, real_type, sizeof(real_type)>(std::forward<E>(e));
                       ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcomplex.hpp:85:110: note: in instantiation of function template specialization
      'xt::detail::complex_helper<true>::imag<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
                return detail::complex_helper<xtl::is_complex<typename std::decay_t<E>::value_type>::value>::imag(std::forward<E>(e));
                                                                                                             ^
/Users/scheibler/anaconda3/envs/mixiva/include/xtensor/xcomplex.hpp:131:91: note: in instantiation of function template specialization
      'xt::detail::complex_expression_helper<true>::imag<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
        return detail::complex_expression_helper<is_xexpression<std::decay_t<E>>::value>::imag(std::forward<E>(e));
                                                                                          ^
/Users/scheibler/Documents/Research/Projects/Current/Separation/mixiva/test_xtensor/src/test_cpx_real.cpp:37:20: note: in instantiation of
      function template specialization 'xt::imag<xt::xview<xt::xtensor_container<xt::uvector<std::__1::complex<double>,
      std::__1::allocator<std::__1::complex<double> > >, 2, xt::layout_type::row_major, xt::xtensor_expression_tag> &, int, xt::xall<unsigned
      long> > >' requested here
  std::cout << xt::imag(xt::view(a, 0, xt::all())) << std::endl;
                   ^
2 errors generated.
make[3]: *** [CMakeFiles/test_cpx_real.dir/src/test_cpx_real.cpp.o] Error 1
make[2]: *** [CMakeFiles/test_cpx_real.dir/all] Error 2
make[1]: *** [CMakeFiles/test_cpx_real.dir/rule] Error 2
make: *** [test_cpx_real] Error 2
```

I am on Mac OS Mojave 10.14.4, using 
```
> gcc --version
Configured with: --prefix=/Applications/Xcode.app/Contents/Developer/usr --with-gxx-include-dir=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/c++/4.2.1
Apple LLVM version 10.0.1 (clang-1001.0.46.4)
Target: x86_64-apple-darwin18.5.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
```


Discussion / hints:
Thanks for reporting!

I can reproduce this compiler error
Yes, this is the same issue as we have in xtensor-r with reducers on complex expressions.

I will work on the fix when back from my vacation. In the mean time, a workaround may be to assign the sum to an allocated complex tensor.

Fix patch:
diff --git a/include/xtensor/xfunctor_view.hpp b/include/xtensor/xfunctor_view.hpp
index e1ae863ff..9542c7065 100644
--- a/include/xtensor/xfunctor_view.hpp
+++ b/include/xtensor/xfunctor_view.hpp
@@ -198,7 +198,7 @@ namespace xt
 
         template <class FCT = functor_type>
         auto data_element(size_type i) const
-            -> decltype(std::declval<FCT>()(std::declval<undecay_expression>().data_element(i)))
+            -> decltype(std::declval<FCT>()(std::declval<const undecay_expression>().data_element(i)))
         {
             return m_functor(m_e.data_element(i));
         }
@@ -1097,7 +1097,7 @@ namespace xt
     template <layout_type L>
     inline auto xfunctor_applier_base<D>::crbegin() const noexcept
     {
-        return xfunctor_iterator<functor_type, decltype(m_e.template rbegin<L>())>
+        return xfunctor_iterator<const functor_type, decltype(m_e.template rbegin<L>())>
             (m_e.template rbegin<L>(), &m_functor);
     }
 
@@ -1110,7 +1110,7 @@ namespace xt
     template <layout_type L>
     inline auto xfunctor_applier_base<D>::crend() const noexcept
     {
-        return xfunctor_iterator<functor_type, decltype(m_e.template rend<L>())>
+        return xfunctor_iterator<const functor_type, decltype(m_e.template rend<L>())>
             (m_e.template rend<L>(), &m_functor);
     }
     //@}
diff --git a/include/xtensor/xview.hpp b/include/xtensor/xview.hpp
index ec91c526f..e6ab65587 100644
--- a/include/xtensor/xview.hpp
+++ b/include/xtensor/xview.hpp
@@ -413,7 +413,7 @@ namespace xt
                                                           get_strides_t<shape_type>>;
 
         using strides_type = get_strides_t<shape_type>;
-        using back_strides_type = strides_type;
+        using backstrides_type = strides_type;
 
 
         using slice_type = std::tuple<S...>;
@@ -430,6 +430,9 @@ namespace xt
                                                           typename xexpression_type::const_storage_iterator,
                                                           typename iterable_base::const_storage_iterator>;
 
+        using reverse_storage_iterator = std::reverse_iterator<storage_iterator>;
+        using const_reverse_storage_iterator = std::reverse_iterator<const_storage_iterator>;
+
         using container_iterator = pointer;
         using const_container_iterator = const_pointer;
         constexpr static std::size_t rank = SIZE_MAX;
@@ -524,6 +527,14 @@ namespace xt
         std::enable_if_t<has_data_interface<T>::value && is_strided_view, storage_iterator>
         storage_end();
 
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_storage_iterator>
+        storage_begin() const;
+
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_storage_iterator>
+        storage_end() const;
+        
         template <class T = xexpression_type>
         std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_storage_iterator>
         storage_cbegin() const;
@@ -532,6 +543,30 @@ namespace xt
         std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_storage_iterator>
         storage_cend() const;
 
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_storage_iterator>
+        storage_rbegin();
+
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_storage_iterator>
+        storage_rend();
+
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+        storage_rbegin() const;
+
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+        storage_rend() const;
+
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+        storage_crbegin() const;
+
+        template <class T = xexpression_type>
+        std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+        storage_crend() const;
+
         template <class T = xexpression_type>
         std::enable_if_t<has_data_interface<T>::value && is_strided_view, const inner_strides_type&>
         strides() const;
@@ -1136,6 +1171,22 @@ namespace xt
         return m_e.storage().begin() + data_offset() + this->size();
     }
 
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_begin() const
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_storage_iterator>
+    {
+        return storage_cbegin();
+    }
+
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_end() const
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_storage_iterator>
+    {
+        return storage_cend();
+    }
+
     template <class CT, class... S>
     template <class T>
     auto xview<CT, S...>::storage_cbegin() const
@@ -1152,6 +1203,54 @@ namespace xt
         return m_e.storage().cbegin() + data_offset() + this->size();
     }
 
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_rbegin()
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_storage_iterator>
+    {
+        return reverse_storage_iterator(storage_end());
+    }
+
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_rend()
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, reverse_storage_iterator>
+    {
+        return reverse_storage_iterator(storage_begin());
+    }
+
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_rbegin() const
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+    {
+        return storage_crbegin();
+    }
+
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_rend() const
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+    {
+        return storage_crend();
+    }
+
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_crbegin() const
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+    {
+        return const_reverse_storage_iterator(storage_end());
+    }
+
+    template <class CT, class... S>
+    template <class T>
+    auto xview<CT, S...>::storage_crend() const
+        -> std::enable_if_t<has_data_interface<T>::value && is_strided_view, const_reverse_storage_iterator>
+    {
+        return const_reverse_storage_iterator(storage_begin());
+    }
+
     /**
      * Return the strides for the underlying container of the view.
      */


Test patch:
diff --git a/test/test_xcomplex.cpp b/test/test_xcomplex.cpp
index 736baea65..3f838b9b0 100644
--- a/test/test_xcomplex.cpp
+++ b/test/test_xcomplex.cpp
@@ -18,6 +18,8 @@
 #include "xtensor/xio.hpp"
 #include "xtensor/xnorm.hpp"
 
+#include "xtensor/xview.hpp"
+
 namespace xt
 {
     using namespace std::complex_literals;
@@ -317,4 +319,26 @@ namespace xt
         auto simd_loaded = a.template load_simd<xt_simd::aligned_mode, complex_type, xt_simd::simd_traits<complex_type>::size>(0);
         (void)simd_loaded;
     }
+
+    TEST(xcomplex, view)
+    {
+
+        using cpx = std::complex<double>;
+        xt::xtensor<cpx, 2> a = {
+            { cpx(1, 1), cpx(-1, 1), cpx(-2, -2) },
+            { cpx(-1, 0), cpx(0, 1), cpx(2, 2) }
+        };
+
+        xtensor<cpx, 1> c = conj(view(a, 0, xt::all()));
+        xtensor<cpx ,1> exp_conj = {cpx(1, -1), cpx(-1, -1), cpx(-2, 2)};
+        EXPECT_EQ(c, exp_conj);
+
+        xtensor<double, 1> r = real(view(a, 0, xt::all()));
+        xtensor<double, 1> exp_real = {double(1), double(-1), double(-2)};
+        EXPECT_EQ(r, exp_real);
+
+        xtensor<double, 1> im = imag(view(a, 0, xt::all()));
+        xtensor<double, 1> exp_im = {double(1), double(1), double(-2)};
+        EXPECT_EQ(im, exp_im);
+    }
 }