Generic container assignment For setters that set a member collection, I write template functions so as to accept any collection type as input:

class HasItems
{
public:
    template &lt;typename C&gt;
    void items(const C&amp; items) {
        // Copy-and-swap omitted
        m_items.assign(std::begin(items), std::end(items));
    }

private:
    std::vector&lt;Item&gt; m_items;
}


But suppose Item is big, and I want to move them around instead of copy if possible.  And furthermore, suppose someone passed me an xvalue std::vector&lt;Item&gt;; I could just move that whole container into place and avoid touching the elements at all!  That looks like this:

class HasItems
{
public:
    template &lt;typename C&gt;
    void items(C&amp;&amp; items) {
        // Helper function implemented below
        assign(m_items, std::forward&lt;C&gt;(items));
    }

private:
    std::vector&lt;Item&gt; m_items;
}

// Assigns the contents of src to dest, moving as much as possible
template &lt;typename C1, typename C2&gt;
void assign(C1&amp; dest, C2&amp;&amp; src) {
    assign(dest, std::forward&lt;C2&gt;(src), std::is_assignable&lt;C1&amp;, C2&amp;&amp;&gt;{});
}

// Called if we can use operator=
template &lt;typename C1, typename C2&gt;
void assign(C1&amp; dest, C2&amp;&amp; src, std::true_type use_equals) {
    dest = std::forward&lt;C2&gt;(src);
}

// Called if we must use dest.assign()
template &lt;typename C1, typename C2&gt;
void assign(C1&amp; dest, C2&amp;&amp; src, std::false_type use_equals) {
    assign_elements(dest, std::forward&lt;C2&gt;(src), std::is_rvalue_reference&lt;C2&amp;&amp;&gt;{});
}

// Called if we can move the elements
template &lt;typename C1, typename C2&gt;
void assign_elements(C1&amp; dest, C2&amp;&amp; src, std::true_type move) {
    dest.assign(std::make_move_iterator(std::begin(src)),
                std::make_move_iterator(std::end(src)));
}

// Called if we must copy the elements
template &lt;typename C1, typename C2&gt;
void assign_elements(C1&amp; dest, C2&amp;&amp; src, std::false_type move) {
    dest.assign(std::begin(src), std::end(src));
}


Is this a good approach?  In particular, is there a nice way to avoid the tag dispatch on std::is_rvalue_reference&lt;C2&amp;&amp;&gt; in the assign_elements() case?  (It was avoided in the operator= case by using dest = std::forward&lt;C2&gt;(src) instead of using std::move() conditionally.)  It seems to pass my simple set of unit tests.
I've implemented this idiom and discovered a major caveat after a few weeks: it doesn't play nicely with boost::iterator_range or other collection views.  An example:

std::vector&lt;std::string&gt; dest;
std::list&lt;std::string&gt; src{"foo", "bar"};
// Moves elements out of src, expected
assign(dest, std::move(src));

src = {"foo", "bar"};
// Also moves elements out of src!!!
assign(dest, boost::make_iterator_range(src));


This happens because boost::make_iterator_range(src) is an xvalue.  I don't see a good way to distinguish between "container" (meaning safe to move from xvalues) and "container view" (meaning not safe to move from).