成员函数.begin()和std :: begin() [英] Member function .begin() and std::begin()
问题描述
调用 std :: vector
和 std的成员函数
on rvalues会产生不同的输出,如下面的测试所示: .begin()
:: begin()
Calling the member function .begin()
of std::vector
and std::begin()
on rvalues result in different outputs, as the following test shows:
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 / code>调用
const&
重载(因为它缺少&&
重载)它返回一个 const_iterator
对象。因此,返回值可以分配给 const_iterator
,但不是迭代器。
Here is my understanding: std::begin()
calls const&
overload (since it lack &&
overload), and therefore, it return a const_iterator
object. So, the returned value can be assigned to const_iterator
but not iterator.
- 我的理解是否正确?
- 为什么
std :: begin()
有一个右值超载?
- Is my understanding correct?
- Why does
std::begin()
not have an rvalue overload?
只是一个注意,我使用 move(a)
来证明在rvalues上调用 .begin()
和 std :: begin()
当然,它可以被 .begin()
和 std :: begin()
Just a note that I used move(a)
to demonstrate calling .begin()
and std::begin()
on rvalues. Of course, it can be replaced by any rvalue object for which .begin()
and std::begin()
are well defined.
编辑:这是一个真实的示例,显示我遇到此问题的位置。我简化了很多只是为了表达的想法,其中 std :: begin()
在右值被调用。所以,因为 row_matrix
是一个代理类,所以不应该有任何问题调用 begin
和
Here is the real example showing where I encountered this issue. I've simplified a lot just to convey the idea where std::begin()
is called on an rvalue. So, since row_matrix
is a proxy class, there shouldn't be any problem calling begin
and end
on rvalues since the underlying object is identical.
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
}
推荐答案
重载 .begin()
通过调用对象的rvalue / lvalue-ness是不可能的。
Until recently, overloading .begin()
by rvalue/lvalue-ness of the invoking object was not possible.
打破现有的代码是不好的,足够糟糕的是遗留的怪癖留在相当强的证据表明这样的代码不存在,有明确的诊断,和/或更改的效果是非常有用的。
Breaking existing code is bad, bad enough that legacy quirks are left in barring reasonably strong evidence that such code does not exist, that there would be clear diagnostics, and/or the effect of the change is really useful.
因此。 begin()
忽略其 * this
的重要性。
除了可能希望与 .begin()
的兼容性
There is no such restriction on std::begin
, other than possibly wishing compatibility with .begin()
.
理论上,标准容器在右值上下文中没有适当的调用来调用 std :: begin
。与 std :: move
或rvalues交互的正确方式是,在调用完成后,您不应该关心移动对象的状态。
In theory, standard containers don't have a proper respose to being called with std::begin
in an rvalue context. The "proper" way of interacting with std::move
or rvalues is that you aren't supposed to care about the state of the moved-from object after the call completes.
这意味着(逻辑上)你只能得到两个迭代器之一(begin或end)。
This means (logically) you can only get one of the two iterators out (begin or end).
在这种情况下,正确的语义是一个大的困惑。我写了适配器,在这种情况下(一个伪开始/结束调用一个右值)生成移动迭代器(例如),但这样做一般是非常令人惊讶的,我认为这是一个坏的举动到底。
What the proper semantics are in this case is a big puzzling. I have written adaptors that, in this situation (a pseudo-begin/end call on an rvalue) generate move iterators (for example), but doing that in general is very surprising, and I think it is a bad move in the end.
这篇关于成员函数.begin()和std :: begin()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!