我正在为容器类型创建一个方便的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
答案 0 :(得分:14)
由于这是language-lawyer,[expr.pre.increment]和[expr.post.increment]都有以下限制:
操作数应是可修改的左值。
现在,vec.end()
和arr.end()
都不是左值,但它们的两种类型都是实现定义的(array和vector)。在这两种情况下,一个简单的指针将满足这些容器的所有迭代器要求 - 这将是一个使用内置前缀和后缀增量的类型。在这种情况下,由于所引用的限制,--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()
是T
,std::vector
或std::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;
}