检查范围内的元素是否可以移动?

时间:2019-05-12 05:56:55

标签: c++ c++20

我正在尝试使用c ++ 20的range接口,并添加了一个构造函数,该构造函数以类似容器的类型接受一个范围。

class element {
  ...
};

class myclass {
public:
  template <typename Iter>
  myclass(Iter first, Iter last)
    : els(first, last)
  { }

  template <typename Range>
  myclass(Range&& r);

private:
  std::vector<element> els;
};

迭代器对版本非常简单。在els_(first, last);中,如果Iter是普通迭代器,它将复制元素;如果Iter是可移动迭代器,例如std::move_iterator<>,它将移动元素。如果调用者希望元素移动,则调用者有责任明确给出可移动的迭代器。

但是,在范围版本中,尽管我可以检查范围本身是在右值引用还是左值引用中给出的,但这无助于检查元素是否可以移动。

假设我们有一个范围生成器make_range(),它使用一个容器并返回一个组成范围概念的代理实例。在以下代码中,构造函数的Range在两种情况下都是右值引用,但显然在第二种情况下不应移动元素。

std::list<element> list_of_elements{...};
myclass c(std::move(list_of_elements)); // should be moved

std::list<element> list_of_elements_to_be_reused{...};
myclass c(make_range(list_of_elements_to_be_reused)); // should not be moved

如何检查给定范围是否用于复制以进行移动?

1 个答案:

答案 0 :(得分:2)

你不知道。您信任std::ranges::begin返回的迭代器,就像您信任迭代器Iter做正确的事情一样。您的第二个构造函数可以只委托:

template <std::ranges::Range Range> // Constraints checked with the library concept
myclass(Range&& r) : myclass(std::ranges::begin(std::move(r)), std::ranges::end(std::move(r)))
{}

要复制默认行为 ,这很明智。但是由于std::ranges::begin是自定义点对象,因此它可以由ADL处理用户定义的begin重载。对于用户定义的类型,此设置:

namespace myns {
    class myclass { /* ... */ };
    auto begin(std::vector<myclass>&& v) { return std::make_move_iterator(v.begin()); }
    auto end(std::vector<myclass>&& v) { /* ... * }
}

在向类构造函数传递右值向量时,将使std::ranges::begin调用myns::begin。是用户定义的类型来控制行为,这很好。

相关问题