title: std::forward and rvalue references in a class
body: <p>I've been reading about <a href="https://stackoverflow.com/questions/3582001/what-are-the-main-purposes-of-using-stdforward-and-which-problems-it-solves"><code>std::forward</code></a> and I think I understand it well, but I don't think I understand it well enough to use it proficiently enough.</p>
  <p>I have a template class that implements a container and has a method called <code>insert</code>. I wanted this method to accept constant references and <em>rvalue</em> references so that if the inserted element is a rvalue reference, it is moved into the container, not copied. For this, I first overloaded the <code>insert</code> method like this:</p>
  <pre><code>template &lt;typename U&gt;
  void do_some_work(U&amp;&amp; x) noexcept
  {
      m_data = std::forward&lt;U&gt;(x);
  }
  void insert(const T&amp; x) 
  {
      do_some_work(x);
  }
  void insert(T&amp;&amp; x) {
      do_some_work(std::forward&lt;T&gt;(x);
  }
  </code></pre>
  <p>The problem is, these two functions now have to call an &quot;inner&quot; function that implements the assertion. If the functions are small, I guess this is not a problem, but if they are large, it is best to use templates, like this</p>
  <pre><code>template &lt;typename U&gt;
  void insert(U&amp;&amp; x) 
  {
      do_some_work(std::forward&lt;U&gt;(x);
  }
  </code></pre>
  <p><strong>QUESTION 1</strong>: Is this correct?</p>
  <hr />
  <p>Now, I want to do the same but with <code>std::vector</code>.</p>
  <pre><code>void insert_vector(const std::vector&lt;T&gt;&amp; v) noexcept {
      for (std::size_t i = 0; i &lt; v.size(); ++i) {
          do_some_work(v[i]);
      }
  }
  void insert_vector(std::vector&lt;T&gt;&amp;&amp; v) noexcept 
  {
      for (std::size_t i = 0; i &lt; v.size(); ++i) 
      {
          do_some_work(std::forward&lt;T&gt;(v[i]));
      }
  }
  </code></pre>
  <p><strong>QUESTION 2</strong>: How do I collapse the <code>insert_vector</code> functions into a single one so that the call to <code>do_some_work</code> is done with</p>
  <ul>
  <li>rvalue references when the vector is a rvalue reference (specified with <code>std::move</code>, for example),</li>
  <li>constant reference when the vector is not given as an rvalue reference, like in <code>(4)</code> of the MWE below. The following does not work for me</li>
  </ul>
  <pre><code>template &lt;typename U&gt;
  void insert_vector(U&amp;&amp; v) noexcept 
  {
      for (std::size_t i = 0; i &lt; v.size(); ++i) 
      {
          do_some_work(std::forward&lt;T&gt;(v[i]));
      }
  }
  </code></pre>
  <hr />
  <p>Here is a minimum working example:</p>
  <pre><code>#include &lt;iostream&gt;
  #include &lt;vector&gt;
  
  template &lt;typename T&gt;
  class my_class 
  {
  private:
      T m_data;
  
  private:
      template &lt;typename U&gt;
      void do_some_more_work(U&amp;&amp; x) noexcept {
          m_data = std::forward&lt;U&gt;(x);
      }
      template &lt;typename U&gt;
      void do_some_work(U&amp;&amp; x) noexcept {
          do_some_more_work(std::forward&lt;U&gt;(x));
      }
  
  public:
      void insert(const T&amp; x) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          do_some_work(x);
      }
      void insert(T&amp;&amp; x) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          do_some_work(std::forward&lt;T&gt;(x));
      }
      void insert_vector(const std::vector&lt;T&gt;&amp; v) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          for (std::size_t i = 0; i &lt; v.size(); ++i) {
              do_some_work(v[i]);
          }
      }
      void insert_vector(std::vector&lt;T&gt;&amp;&amp; v) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          for (std::size_t i = 0; i &lt; v.size(); ++i) {
              do_some_work(std::forward&lt;T&gt;(v[i]));
          }
      }
  };
  
  struct my_struct {
      my_struct() noexcept = default;
      my_struct(int v) noexcept : m_v(v) { }
      my_struct(const my_struct&amp; s) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          m_v = s.m_v;
      }
      my_struct(my_struct&amp;&amp; s) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          m_v = std::move(s.m_v); // not need, but whatever
          s.m_v = -1;
      }
      my_struct&amp; operator= (const my_struct&amp; s) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          m_v = s.m_v;
          return *this;
      }
      my_struct&amp; operator= (my_struct&amp;&amp; s) noexcept {
          std::cout &lt;&lt; __PRETTY_FUNCTION__ &lt;&lt; '\n';
          m_v = std::move(s.m_v); // not need, but whatever
          s.m_v = -1;
          return *this;
      }
      int m_v;
  };
  
  int main() {
      my_class&lt;my_struct&gt; mc;
  
      std::cout &lt;&lt; &quot;===========================================\n&quot;;
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(1.1)\n&quot;;
      my_struct s{3};
      std::cout &lt;&lt; s.m_v &lt;&lt; '\n';
      mc.insert(s);
      std::cout &lt;&lt; s.m_v &lt;&lt; '\n';
      }
  
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(1.2)\n&quot;;
      const my_struct s{3};
      std::cout &lt;&lt; s.m_v &lt;&lt; '\n';
      mc.insert(s);
      std::cout &lt;&lt; s.m_v &lt;&lt; '\n';
      }
  
      std::cout &lt;&lt; &quot;===========================================\n&quot;;
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(2.1)\n&quot;;
      mc.insert(my_struct{5});
      }
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(2.2)\n&quot;;
      my_struct s{5};
      std::cout &lt;&lt; s.m_v &lt;&lt; '\n';
      mc.insert(std::move(s));
      std::cout &lt;&lt; s.m_v &lt;&lt; '\n';
      }
  
      std::cout &lt;&lt; &quot;===========================================\n&quot;;
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(3.1)\n&quot;;
      std::vector&lt;my_struct&gt; v(5);
      for (std::size_t i = 0; i &lt; v.size(); ++i) { v[i] = my_struct(i); }
  
      for (const auto&amp; s : v) { std::cout &lt;&lt; s.m_v &lt;&lt; ' '; } std::cout &lt;&lt; '\n';
      mc.insert_vector(v);
      for (const auto&amp; s : v) { std::cout &lt;&lt; s.m_v &lt;&lt; ' '; } std::cout &lt;&lt; '\n';
      }
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(3.2)\n&quot;;
      const std::vector&lt;my_struct&gt; v = []() {
          std::vector&lt;my_struct&gt; v(5);
          for (std::size_t i = 0; i &lt; v.size(); ++i) { v[i] = my_struct(i); }
          return v;
      }();
  
      for (const auto&amp; s : v) { std::cout &lt;&lt; s.m_v &lt;&lt; ' '; } std::cout &lt;&lt; '\n';
      mc.insert_vector(v);
      for (const auto&amp; s : v) { std::cout &lt;&lt; s.m_v &lt;&lt; ' '; } std::cout &lt;&lt; '\n';
      }
  
      std::cout &lt;&lt; &quot;===========================================\n&quot;;
      {
      std::cout &lt;&lt; &quot;-------------------------------------------\n&quot;;
      std::cout &lt;&lt; &quot;(4)\n&quot;;
      std::vector&lt;my_struct&gt; v(5);
      for (std::size_t i = 0; i &lt; v.size(); ++i) { v[i] = my_struct(i); }
  
      for (const auto&amp; s : v) { std::cout &lt;&lt; s.m_v &lt;&lt; ' '; } std::cout &lt;&lt; '\n';
      mc.insert_vector(std::move(v));
      for (const auto&amp; s : v) { std::cout &lt;&lt; s.m_v &lt;&lt; ' '; } std::cout &lt;&lt; '\n';
      }
  }
  </code></pre>