为什么我不能减少std :: array :: end()?

时间:2018-01-10 12:44:30

标签: c++ iterator language-lawyer stdarray

我正在为容器类型创建一个方便的display()函数模板。最后一个元素的输出与其余元素不同,因此我检查myIterator != --cont.cend();时间。这适用于std::vector,但不适用于std::array。为什么呢?

这是一个MWE(不是我的实际代码):

std::vector<double> vec({1,2});
std::array<double, 2> arr({{1,2}});
auto vecIt = --vec.end(); // OK
auto arrIt = --arr.end(); // error: lvalue required as decrement operand

4 个答案:

答案 0 :(得分:14)

由于这是[expr.pre.increment][expr.post.increment]都有以下限制:

  

操作数应是可修改的左值。

现在,vec.end()arr.end()都不是左值,但它们的两种类型都是实现定义的(arrayvector)。在这两种情况下,一个简单的指针将满足这些容器的所有迭代器要求 - 这将是一个使用内置前缀和后缀增量的类型。在这种情况下,由于所引用的限制,--c.end()将是不正确的。但是,如果迭代器类型是类类型,则上述限制不适用 - 因为我们不使用内置增量运算符 - 并且在上面调用operator--() class没有这个限制(尽管它可以,如果成员函数是lvalue-reference-qualified)。

因此,对于向量或数组,--c.end()保证不起作用,因为如果end()返回指针,则表示格式错误,并且end()被允许返回一个指针。在您的特定实施中,vector iterator具有类类型,但array&#39; s iterator只是指针类型,这就是为什么前者虽然有效,但后者没有。

首选std::prev(c.end()),它适用于所有实施的两种容器类型。

答案 1 :(得分:7)

永远不会递减rvalue,即使它恰好编译。这对代码的读者来说是不直观的。

改为使用std::prev

auto it = std::prev(arr.end());

答案 2 :(得分:3)

这是C ++标准中的事实。

如果--T.end()Tstd::vectorstd::list,则

std::deque必须有效。这是正确的,包括C ++ 11;之后就有了放松。

答案 3 :(得分:2)

这取决于迭代器的定义方式。

似乎对于类模板std::array,迭代器被定义为指针。所以功能开始,结束。 cbegin,cend只返回指针。因此,当指针按值返回时,您可能不会减少它,因为需要lvalue ..

对于类模板std::vector,迭代器被定义为用户定义的类,其中定义了运算符 - ()。

考虑以下示范程序

#include <iostream>

class Int
{
public:
    Int( int x = 0 ) : x ( x ) 
    {

    }

    Int & operator --()
    {
        --x;
        return *this;
    }

    friend std::ostream & operator <<( std::ostream &os, const Int &i )
    {
        return os << i.x;
    }
private:
    int x;
};

int f( int x )
{
    return x;
}

Int f( Int x )
{
    return x;
}

int main() 
{
    std::cout << --f( Int( 10 ) ) << std::endl;
//  error: lvalue required as decrement operand
//  std::cout << --f( 10 ) << std::endl;

    return 0;
}

考虑到你可以写

auto arrIt = std::prev( arr.end() );

而不是

auto arrIt = --arr.end();

如果您包含标题<iterator>

您可以将运算符与类模板std::array的反向迭代器一起使用,因为标准明确定义了它们,如

typedef std::reverse_iterator<iterator> reverse_iterator;
typedef std::reverse_iterator<const_iterator> const_reverse_iterator;

并且用户定义的类std::reverse_iterator定义operator --()

这是一个示范程序

#include <iostream>
#include <array>

int main() 
{
    std::array<double, 2> arr = { { 1, 2 } };

    auto it = --arr.rend();

    std::cout << *it << std::endl;

    return 0;
}