在右值上调用.begin()
和std::vector
的成员函数std::begin()
会导致不同的输出,如以下测试所示:
vector<int> a{ 1, 2, 3 };
vector<int>::iterator it1 = move(a).begin(); // OK
vector<int>::const_iterator it2 = move(a).begin(); // OK
vector<int>::iterator it3 = begin(move(a)); // Error!
vector<int>::const_iterator it4 = begin(move(a)); // OK
这是我的理解:
std::begin()
调用const&
重载(因为它没有&&
重载),因此,它返回const_iterator
对象。因此,可以将返回值分配给const_iterator
,但不能分配给iterator.
std::begin()
没有右值过载? 请注意,我使用
move(a)
演示了如何在rvalues上调用.begin()
和std::begin()
。当然,可以用定义了.begin()
和std::begin()
的任何右值对象代替它。编辑:这是显示我在哪里遇到此问题的真实示例。我已经简化了很多,只是为了传达在右值上调用
std::begin()
的想法。因此,由于row_matrix
是代理类,因此在rvalues上调用begin
和end
应该没有任何问题,因为基础对象是相同的。class matrix_row;
class row_iterator;
class matrix {
public:
matrix_row row(int i);
// other members
};
class matrix_row { // <- proxy class representing a row of matrix
public:
row_iterator begin();
row_iterator end();
// other members
private:
int row_;
matrix& matrix_;
};
class row_iterator {
// defined everything needed to qualify as a valid iterator
};
matrix m(3,4);
for(auto x = m.row(1).begin(); x != m.row(1).end(); ++x) {
*x /=2; // OK
}
for(auto x = begin(m.row(1)); x != end(m.row(1)); ++x) {
*x /= 2; // Error
}
最佳答案
直到最近,还不可能通过调用对象的rvalue / lvalue-ness重载.begin()
。
从理论上讲,将其添加到标准库中后,如果将其修改,可能会破坏现有代码。
破坏现有代码是很糟糕的,非常糟糕,以至于遗留了一些古怪的怪癖,以排除相当有力的证据表明此类代码不存在,有明确的诊断信息和/或更改的影响确实有用。
因此.begin()
忽略了其*this
的右值性。
除了可能希望与std::begin
兼容之外,对.begin()
没有任何限制。
从理论上讲,标准容器在右值上下文中没有适当的位置来使用std::begin
进行调用。与std::move
或rvalues交互的“正确”方法是,在调用完成后,您不必考虑移出对象的状态。
这意味着(从逻辑上来说)您只能获得两个迭代器之一(开始或结束)。
在这种情况下,正确的语义是一个很大的困惑。我已经编写了适配器,在这种情况下(例如,对rvalue的伪开始/结束调用)生成了移动迭代器(例如),但是这样做通常是非常令人惊讶的,并且我认为这最终是一个不好的举动。
关于c++ - 成员函数.begin()和std::begin(),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/37262329/