对于设置成员集合的setter,我编写模板函数以便接受任何集合类型作为输入:
class HasItems
{
public:
template <typename C>
void items(const C& items) {
// Copy-and-swap omitted
m_items.assign(std::begin(items), std::end(items));
}
private:
std::vector<Item> m_items;
}但是假设Item很大,如果可能的话,我想移动它们而不是复制。此外,假设有人向我传递了一个xvalue std::vector<Item>;我可以将整个容器移到适当的位置,并完全避免接触元素!看起来是这样的:
class HasItems
{
public:
template <typename C>
void items(C&& items) {
// Helper function implemented below
assign(m_items, std::forward<C>(items));
}
private:
std::vector<Item> m_items;
}
// Assigns the contents of src to dest, moving as much as possible
template <typename C1, typename C2>
void assign(C1& dest, C2&& src) {
assign(dest, std::forward<C2>(src), std::is_assignable<C1&, C2&&>{});
}
// Called if we can use operator=
template <typename C1, typename C2>
void assign(C1& dest, C2&& src, std::true_type use_equals) {
dest = std::forward<C2>(src);
}
// Called if we must use dest.assign()
template <typename C1, typename C2>
void assign(C1& dest, C2&& src, std::false_type use_equals) {
assign_elements(dest, std::forward<C2>(src), std::is_rvalue_reference<C2&&>{});
}
// Called if we can move the elements
template <typename C1, typename C2>
void assign_elements(C1& dest, C2&& 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 <typename C1, typename C2>
void assign_elements(C1& dest, C2&& src, std::false_type move) {
dest.assign(std::begin(src), std::end(src));
}这样做好吗?特别是,在std::is_rvalue_reference<C2&&>的情况下,是否有一种很好的方法来避免assign_elements()上的标记分派?(在operator=情况下,通过使用dest = std::forward<C2>(src)而不是有条件地使用std::move()避免了这种情况。)它似乎通过了我简单的单元测试集。
发布于 2015-04-09 22:14:00
我已经实现了这个成语,几周后我发现了一个重要的警告:它不能很好地处理boost::iterator_range或其他集合视图。举个例子:
std::vector<std::string> dest;
std::list<std::string> 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));这是因为boost::make_iterator_range(src)是一个xvalue。我看不到区分“容器”(表示从xvalue移动安全)和“容器视图”(意思是移动不安全)的好方法。
https://codereview.stackexchange.com/questions/83443
复制相似问题