检查范围的元素是否可以移动?
check if elements of a range can be moved?
我正在尝试 c++20 的范围接口,我添加了一个构造函数,该构造函数在我的类似容器的类型中采用范围。
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
如何检查给定的范围是否用于复制以进行移动?
你没有。你信任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
。控制行为的是用户定义的类型,这很好。
相关文章:
- 当有分配器意识的容器被复制/移动时,反弹分配器是否被复制/移走
- 移动后是否需要重置标准::列表?
- 是否可以在C++中移动临时对象的属性?
- C++ 移动语义是否在任何情况下都能节省资源?
- 如果这不是类的"复制构造函数",是否可以移动对象?
- vector是否为std::移动的对象连续分配内存
- 是否可以避免在以下代码中复制/移动构造函数的需要?
- 移动构造函数是否C++过时?
- 如何获取类型是否真正可移动可构造
- 使用 std::move 将参数传递给函数,如果该参数声明为按值传递或使用移动操作数 &&,是否有区别?
- 是否允许将列移动到索引 0?
- 是否可以通过使用移动/交换 c++11 来延长返回的临时变量的生命周期
- 移动 std::bitset<N> 是否超过 N 个位置未定义的行为?
- 我是否缺少<实验/文件系统>移动操作?
- 是否可以将移动的变量标记为不再可用,并在使用它时收到编译器警告?
- 返回 *&object 时是否允许复制/移动省略?
- 如果没有带有函数签名的 rvalue 参数,是否会执行 C++ 11 中的移动语义?
- 是否有可能具有放入容器的移动操作的类型?
- 移动是否分配了 std::fstream 关闭原始流
- 移动是否使对象处于可用状态