title: How to check whether elements of a range should be moved?
body: <p>There's a similar question: <a href="https://stackoverflow.com/questions/56096579/check-if-elements-of-a-range-can-be-moved">check if elements of a range can be moved?</a></p>
  <p>I don't think the answer in it is a nice solution. Actually, it requires partial specialization for all containers.</p>
  <hr />
  <p>I made an attempt, but I'm not sure whether checking <code>operator*()</code> is enough.</p>
  <pre><code>// RangeType
  
  using IteratorType = std::iterator_t&lt;RangeType&gt;;
  using Type = decltype(*(std::declval&lt;IteratorType&gt;()));
  
  constexpr bool canMove = std::is_rvalue_reference_v&lt;Type&gt;;
  </code></pre>
  <hr />
  <h1>Update</h1>
  <p>The question may could be split into 2 parts:</p>
  <ol>
  <li>Could algorithms in STL like <code>std::copy</code>/<code>std::uninitialized_copy</code> actually avoid unnecessary deep copy when receiving elements of r-value?</li>
  <li>When receiving a <em><strong>range of r-value</strong></em>, how to check if it's a <a href="https://en.cppreference.com/w/cpp/ranges#Range_adaptor_objects" rel="nofollow noreferrer">range adapter</a> like <code>std::ranges::subrange</code>, or a container which holds the <strong>ownership</strong> of its elements like <code>std::vector</code>?</li>
  </ol>
  <pre><code>template &lt;typename InRange, typename OutRange&gt;
  void func(InRange&amp;&amp; inRange, OutRange&amp;&amp; outRange) {
      using std::begin;
      using std::end;
      std::copy(begin(inRange), end(inRange), begin(outRange));
      // Q1: if `*begin(inRange)` returns a r-value,
      //     would move-assignment of element be called instead of a deep copy?
  }
  
  std::vector&lt;int&gt; vi;
  std::list&lt;int&gt; li;
  /* ... */
  func(std::move(vi), li2);
  // Q2: Would elements be shallow copy from vi?
  // And if not, how could I implement just limited count of overloads, without overload for every containers?
  // (define a concept (C++20) to describe those who take ownership of its elements)
  </code></pre>
  <p>Q1 is not a problem as @Nicol Bolas , @eerorika and @Davis Herring pointed out, and it's not what I puzzled about.
  (But I indeed think the API is confusing, <code>std::assign</code>/<code>std::uninitialized_construct</code> may be more ideal names)</p>
  <p>@alfC has made a great answer about my question (Q2), and gives a pristine perspective. (move idiom for ranges with ownership of elements)</p>
  <hr />
  <p>To sum up, for most of the current containers (especially those from STL), (and also every range adapter...), partial specialization/overload function for all of them is the only solution, e.g.:</p>
  <pre><code>template &lt;typename Range&gt;
  void func(Range&amp;&amp; range) { /*...*/ }
  
  template &lt;typename T&gt;
  void func(std::vector&lt;T&gt;&amp;&amp; movableRange) {
      auto movedRange = std::ranges::subrange{
          std::make_move_iterator(movableRange.begin()),
          std::make_move_iterator(movableRange.end())
      };
  
      func(movedRange);
  }
  
  // and also for `std::list`, `std::array`, etc...
  </code></pre>