成员函数.begin()和std :: begin() [英] Member function .begin() and std::begin()

查看:474
本文介绍了成员函数.begin()和std :: begin()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

调用 std :: vector std的成员函数 .begin() :: begin() on rvalues会产生不同的输出,如下面的测试所示:

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.


  1. 我的理解是否正确?

  2. 为什么 std :: begin()有一个右值超载?

  1. Is my understanding correct?
  2. 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆