I've been reading about std::forward and I think I understand it well, but I don't think I understand it well enough to use it proficiently enough.
I have a template class that implements a container and has a method called insert. I wanted this method to accept constant references and rvalue 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 insert method like this:
template <typename U>
void do_some_work(U&& x) noexcept
{
    m_data = std::forward<U>(x);
}
void insert(const T& x) 
{
    do_some_work(x);
}
void insert(T&& x) {
    do_some_work(std::forward<T>(x);
}
The problem is, these two functions now have to call an "inner" 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
template <typename U>
void insert(U&& x) 
{
    do_some_work(std::forward<U>(x);
}
QUESTION 1: Is this correct?
Now, I want to do the same but with std::vector.
void insert_vector(const std::vector<T>& v) noexcept {
    for (std::size_t i = 0; i < v.size(); ++i) {
        do_some_work(v[i]);
    }
}
void insert_vector(std::vector<T>&& v) noexcept 
{
    for (std::size_t i = 0; i < v.size(); ++i) 
    {
        do_some_work(std::forward<T>(v[i]));
    }
}
QUESTION 2: How do I collapse the insert_vector functions into a single one so that the call to do_some_work is done with
- rvalue references when the vector is a rvalue reference (specified with std::move, for example),
- constant reference when the vector is not given as an rvalue reference, like in (4)of the MWE below. The following does not work for me
template <typename U>
void insert_vector(U&& v) noexcept 
{
    for (std::size_t i = 0; i < v.size(); ++i) 
    {
        do_some_work(std::forward<T>(v[i]));
    }
}
Here is a minimum working example:
#include <iostream>
#include <vector>
template <typename T>
class my_class 
{
private:
    T m_data;
private:
    template <typename U>
    void do_some_more_work(U&& x) noexcept {
        m_data = std::forward<U>(x);
    }
    template <typename U>
    void do_some_work(U&& x) noexcept {
        do_some_more_work(std::forward<U>(x));
    }
public:
    void insert(const T& x) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        do_some_work(x);
    }
    void insert(T&& x) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        do_some_work(std::forward<T>(x));
    }
    void insert_vector(const std::vector<T>& v) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        for (std::size_t i = 0; i < v.size(); ++i) {
            do_some_work(v[i]);
        }
    }
    void insert_vector(std::vector<T>&& v) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        for (std::size_t i = 0; i < v.size(); ++i) {
            do_some_work(std::forward<T>(v[i]));
        }
    }
};
struct my_struct {
    my_struct() noexcept = default;
    my_struct(int v) noexcept : m_v(v) { }
    my_struct(const my_struct& s) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        m_v = s.m_v;
    }
    my_struct(my_struct&& s) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        m_v = std::move(s.m_v); // not need, but whatever
        s.m_v = -1;
    }
    my_struct& operator= (const my_struct& s) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\n';
        m_v = s.m_v;
        return *this;
    }
    my_struct& operator= (my_struct&& s) noexcept {
        std::cout << __PRETTY_FUNCTION__ << '\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<my_struct> mc;
    std::cout << "===========================================\n";
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(1.1)\n";
    my_struct s{3};
    std::cout << s.m_v << '\n';
    mc.insert(s);
    std::cout << s.m_v << '\n';
    }
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(1.2)\n";
    const my_struct s{3};
    std::cout << s.m_v << '\n';
    mc.insert(s);
    std::cout << s.m_v << '\n';
    }
    std::cout << "===========================================\n";
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(2.1)\n";
    mc.insert(my_struct{5});
    }
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(2.2)\n";
    my_struct s{5};
    std::cout << s.m_v << '\n';
    mc.insert(std::move(s));
    std::cout << s.m_v << '\n';
    }
    std::cout << "===========================================\n";
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(3.1)\n";
    std::vector<my_struct> v(5);
    for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
    for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
    mc.insert_vector(v);
    for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
    }
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(3.2)\n";
    const std::vector<my_struct> v = []() {
        std::vector<my_struct> v(5);
        for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
        return v;
    }();
    for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
    mc.insert_vector(v);
    for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
    }
    std::cout << "===========================================\n";
    {
    std::cout << "-------------------------------------------\n";
    std::cout << "(4)\n";
    std::vector<my_struct> v(5);
    for (std::size_t i = 0; i < v.size(); ++i) { v[i] = my_struct(i); }
    for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
    mc.insert_vector(std::move(v));
    for (const auto& s : v) { std::cout << s.m_v << ' '; } std::cout << '\n';
    }
}
