title: Lazy Math with C++ Ranges
body: <p>I wanted to explore the realm of lazy mathematical operations in c++ using ranges (specifically range-v3), rather than expression templates.  Instead of defining the various operators :<code>operator+</code>, <code>operator-</code>, ... and so on, to accept all ranges, I thought it would be prudent to provide a wrapper class and define the operations on the wrapper class which I've called <code>result_range</code> in the code below.  I'm getting some compiler errors due to how the <code>end_cursor</code> method is implemented.  The code pasted below is also on <a href="https://godbolt.org/z/Ycv663" rel="nofollow noreferrer">godbolt</a>. The code:</p>
  <pre class="lang-cpp prettyprint-override"><code>#include &lt;range/v3/core.hpp&gt;
  #include &lt;range/v3/range/concepts.hpp&gt;
  #include &lt;range/v3/view/repeat.hpp&gt;
  #include &lt;range/v3/view/repeat_n.hpp&gt;
  #include &lt;range/v3/view/zip.hpp&gt;
  #include &lt;range/v3/view/zip_with.hpp&gt;
  #include &lt;range/v3/algorithm/equal.hpp&gt;
  #include &lt;iostream&gt;
  #include &lt;concepts&gt;
  #include &lt;functional&gt;
  
  namespace vs = ranges::views;
  namespace rs = ranges;
  
  template &lt;ranges::input_range R&gt;
  struct result_range;
  
  namespace detail
  {
  // define some traits and concepts to constrain our universal references and ranges
  template &lt;typename = void&gt;
  struct is_result : std::false_type {
  };
  template &lt;typename T&gt;
  struct is_result&lt;result_range&lt;T&gt;&gt; : std::true_type {
  };
  
  template &lt;typename U&gt;
  constexpr bool is_result_v = is_result&lt;std::remove_cvref_t&lt;U&gt;&gt;::value;
  
  } // namespace detail
  
  template &lt;typename T&gt;
  concept Result = detail::is_result_v&lt;T&gt;;
  
  template &lt;typename T&gt;
  concept Numeric = std::integral&lt;T&gt; || std::floating_point&lt;T&gt;;
  
  template &lt;ranges::input_range R&gt;
  struct result_range : ranges::view_facade&lt;result_range&lt;R&gt;&gt; {
  private:
      friend ranges::range_access;
      R r;
  
      struct cursor {
      private:
          using It = ranges::iterator_t&lt;R&gt;;
          It iter;
  
      public:
          // using contiguous = ;
  
          cursor() = default;
          cursor(It it) : iter(it) {}
  
          decltype(auto) read() const { return *iter; }
          decltype(auto) read() { return *iter; }
  
          bool equal(const cursor&amp; other) const { return iter == other.iter; }
  
          void next() { ++iter; }
  
          void prev() requires ranges::bidirectional_iterator&lt;It&gt; { --iter; }
  
          auto distance_to(const cursor&amp; other) const
              -&gt; decltype(ranges::distance(iter, other.iter))
          {
              return ranges::distance(iter, other.iter);
          }
  
          auto advance(std::ptrdiff_t n) -&gt; decltype(ranges::advance(iter, n))
          {
              ranges::advance(iter, n);
          }
      };
  
      cursor begin_cursor() const { return {ranges::begin(r)}; }
      cursor begin_cursor() { return {ranges::begin(r)}; }
  
      cursor end_cursor() const { return {ranges::end(r)}; }
      cursor end_cursor() { return {ranges::end(r)}; }
  
  public:
      result_range() = default;
  
      result_range(R&amp;&amp; r) : r{std::forward&lt;R&gt;(r)} {}
  };
  
  template &lt;typename R&gt;
  result_range&lt;R&gt; result(R&amp;&amp; r)
  {
      return {std::forward&lt;R&gt;(r)};
  }
  
  #define gen_operators(op, f)                                                             \
      template &lt;Result T, Result U&gt;                                                        \
      constexpr auto op(T&amp;&amp; t, U&amp;&amp; u)                                                      \
      {                                                                                    \
          return result(vs::zip_with(f, std::forward&lt;T&gt;(t), std::forward&lt;U&gt;(u)));          \
      }                                                                                    \
      template &lt;Result T, Numeric U&gt;                                                       \
      constexpr auto op(T&amp;&amp; t, U u)                                                        \
      {                                                                                    \
          if constexpr (ranges::sized_range&lt;T&gt;)                                            \
              return result(                                                               \
                  vs::zip_with(f, std::forward&lt;T&gt;(t), vs::repeat_n(u, t.size())));         \
          else                                                                             \
              return result(vs::zip_with(f, std::forward&lt;T&gt;(t), vs::repeat(u)));           \
      }                                                                                    \
      template &lt;Result T, Numeric U&gt;                                                       \
      constexpr auto op(U u, T&amp;&amp; t)                                                        \
      {                                                                                    \
          if constexpr (ranges::sized_range&lt;T&gt;)                                            \
              return result(                                                               \
                  vs::zip_with(f, vs::repeat_n(u, t.size()), std::forward&lt;T&gt;(t)));         \
          else                                                                             \
              return result(vs::zip_with(f, vs::repeat(u), std::forward&lt;T&gt;(t)));           \
      }
  gen_operators(operator+, std::plus{})
  gen_operators(operator-, std::minus{})
  gen_operators(operator*, std::multiplies{})
  gen_operators(operator/, std::divides{})
  
  int main()
  {
      auto x_ = std::vector{1, 2, 3, 4, 5};
      auto y_ = std::vector{-1, -2, -3, -4, -5};
      auto x = result(x_ | vs::all);
      auto y = result(y_ | vs::all);
  
      auto sum = x + y + 2 * x - y + 3 * y;
  
      std::cout &lt;&lt; &quot;sum is 0? &quot; &lt;&lt; rs::equal(sum, vs::repeat_n(0, 5)) &lt;&lt; '\n';
  }
  </code></pre>
  <p>And the first error:</p>
  <pre><code>&lt;source&gt;:134:67:   required from here
  &lt;source&gt;:82:49: error: could not convert '{ranges::_end_::fn::operator()(R&amp;&amp;) const [with R = ranges::zip_with_view&lt;std::multiplies&lt;void&gt;, ranges::repeat_n_view&lt;int&gt;, result_range&lt;ranges::ref_view&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt; &gt; &gt;&amp;; ranges::_end_::fn::_result_t&lt;R&gt; = ranges::iter_zip_with_view&lt;ranges::indirected&lt;std::multiplies&lt;void&gt; &gt;, ranges::repeat_n_view&lt;int&gt;, result_range&lt;ranges::ref_view&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt; &gt; &gt;::sentinel&lt;false&gt;](((result_range&lt;ranges::zip_with_view&lt;std::multiplies&lt;void&gt;, ranges::repeat_n_view&lt;int&gt;, result_range&lt;ranges::ref_view&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt; &gt; &gt; &gt;*)this)-&gt;result_range&lt;ranges::zip_with_view&lt;std::multiplies&lt;void&gt;, ranges::repeat_n_view&lt;int&gt;, result_range&lt;ranges::ref_view&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt; &gt; &gt; &gt;::r)}' from '&lt;brace-enclosed initializer list&gt;' to 'result_range&lt;ranges::zip_with_view&lt;std::multiplies&lt;void&gt;, ranges::repeat_n_view&lt;int&gt;, result_range&lt;ranges::ref_view&lt;std::vector&lt;int, std::allocator&lt;int&gt; &gt; &gt; &gt; &gt; &gt;::cursor'
     82 |     cursor end_cursor() { return {ranges::end(r)}; }
        |                                                 ^
        |                                                 |
        |                                                 &lt;brace-enclosed initializer list&gt;
  
  ASM generation compiler returned: 1
  </code></pre>
  <p>Question: What is the correct way to implement the <code>result_range</code> facade?  Normally I can figure out the correct usage from the extensive tests in range-v3 but there's only one test for <code>view_facade</code> so I can't glean the correct usage.</p>