【问题标题】:error: invalid operands to binary expression when comparing iterators using !=错误:使用 != 比较迭代器时,二进制表达式的操作数无效
【发布时间】:2020-11-10 10:44:40
【问题描述】:

我正在尝试反转 std::string:

void reverseString(vector<char>& s)
{
   auto i = s.begin();
   auto j = s.rbegin();

   while (i != j) 
   {
      char tmp = *i;
      *i = *j;
      *j = tmp;

      i++;
      j--;
   }
}

但是,当我尝试比较迭代器时发生了这种情况

错误

Line 6: Char 17: error: invalid operands to binary expression 
('__gnu_cxx::__normal_iterator<char *, std::vector<char, std::allocator<char> > >' and
'std::reverse_iterator<__gnu_cxx::__normal_iterator<char *, std::vector<char, std::allocator<char> > > >')
        while(i != j) {

【问题讨论】:

  • begin() 和 rbegin() 返回不同的类型。一个是迭代器,另一个是反向迭代器。
  • @dgrandm 选择了我的答案。我希望你不介意。
  • 请查看此gcc.godbolt.org/z/r1vv73 并进行比较。
  • @VarushVarsha 那是仅链接,仅代码和评论中的回答。好的,也许您确实发表了评论而不是回答,因为它是仅链接且仅代码的。请考虑直接在此处做出正确的解释性答案。如果通过解释我可以很容易地看到它比我的答案更好,我会很高兴地投票。
  • 我没有否决你的回答;就正确答案而言,我既没有时间也没有意愿正确参与这个网站。

标签: c++ algorithm iterator reverse stdstring


【解决方案1】:

您的代码中有一些问题:

  • 首先i 的类型为std::vector&lt;char&gt;::iteratorj 类型为std::vector&lt;char&gt;::reverse_iterator,其中 不一样。因此你不能做
    while(i != j) 
    
    这就是编译器错误的原因!
  • 其次,反向迭代器应该与普通迭代器一样。 意思是j--; 将尝试移动一个过去,这是一个结束迭代器,并在调用undefined behaviour 的下一次迭代中取消引用。相反,您应该递增它以从容器的最后一个迭代。
  • 最后但并非最不重要的一点是,您应该只走到容器的一半来反转它。否则,您将交换两次并获得您传递的相同向量。

以下是更正后的代码:See a demo

#include <iostream>
#include <iterator>
#include <algorithm> // std::copy_n, std::swap
#include <vector>

void reverseString(std::vector<char>& s)
{
   auto i = s.begin();
   auto j = s.rbegin();
   const auto half = s.size() / 2u;

   while (i != s.begin() + half || j != s.rbegin() + half)
   {
      // your saping code or simply `std::swap` the elements
      std::swap(*i, *j);
      ++i;
      ++j; // increment both iterators
   }
}

int main()
{
   std::vector<char> vec{ 'a', 'b', 'c' };
   reverseString(vec);
   // print the reversed vector
   std::copy_n(vec.cbegin(), vec.size(), std::ostream_iterator<char>(std::cout, " "));
}

输出

c b a 

附注:

【讨论】:

  • 很公平。您确实有不寻常且非常感谢的解释。我喜欢它作为我更哲学的答案的一种实际导向的兄弟姐妹。 ;-)
  • 让我们看看“last”。我不会对呈现更多不同的角度感到惊讶。
【解决方案2】:

错误信息已经说明了

('__gnu_cxx::__normal_iterator >' 和 'std::reverse_iterator<:__normal_iterator std::vector std ::> > >')

当你删除尖括号内常见的、不相关的东西时,你会得到

__gnu_cxx::__normal_iterator<...> 和 std::reverse_iterator<:__normal_iterator> >

这意味着您有两种不同的类型,没有为它们定义适当的比较运算符。


要解决这个问题,您可以与std::reverse_iterator::base() 进行比较,例如

while (i != j.base()) {
    // ...
}

还要注意

基本迭代器将指向下一个元素 (...) 指向 reverse_iterator 当前指向的元素。

这意味着,您还必须检查一个超出并且循环条件变为

while (i != j.base() && i != j.base() - 1) {
    // ...
}

不相关,但您可以使用std::iter_swap而不是自己手动进行交换

while (i != j.base() && i != j.base() - 1) {
    std::iter_swap(i, j);
    ++i;
    ++j;
}

【讨论】:

    【解决方案3】:

    您似乎知道必须像 *i = *j; 那样取消引用迭代器。
    您还需要在while(i != j) 中执行此操作,因为您可以比较chars,但不能比较迭代器。尤其是不同类型的迭代器,正如 dgrandm 在他的评论中提到的那样。

    while(*i != *j)
    

    这解决了类型问题。
    然而,您实际上可能试图不比较元素的值,而是比较它们在向量中的位置。 IE。为了反转整个向量。
    使用迭代器无法比较位置
    (准确地说:比较较小/较大,请参见下文 Alan Birtles 的赞赏输入)。因为迭代器有意隐藏不同容器之间的差异。向量确实有类似的位置,但其他容器没有。以链表为例。
    您将无法比较链表中的位置,至少不能通过比较迭代器。因此,容器抽象迭代器也隐藏了可比性。这反过来意味着您无法通过迭代器比较位置,即使您当前使用的容器允许这样做。

    澄清:比较迭代器是可能的(比如“这是同一个元素吗?”),正如 Alan Birtles 所提到的,但只是为了相等。但是,您需要的比较是较小/较大(例如“这两个迭代器是否相互传递?”)。如果您想到包含偶数个元素的容器,这一点就会变得很明显。在这种情况下,i++;j--; 两个迭代器永远不会指向同一个元素,你的循环会失败。您可以在更改第二个迭代器之前和之后进行相等检查,如果您正在使用的两个不同的迭代器可以这样做的话。

    【讨论】:

    • 我会对投反对票的原因感兴趣。请注意,我的答案与我使用的评论不同,并且我只是在完成编辑和发布后找到它时才将其添加为详细信息。如果反对意见是评论作者,请告诉我。我将删除评论详细信息。
    • 这可能是由于不正确。比较迭代器运行循环,直到 positions 相等。比较值会运行循环,直到 元素 相等,这对于反转没有用。
    • @SaiSreenivas 好点。你是说除了类型问题还有更多需要解决的问题。我会合并的。
    • @chris 同上。谢谢。
    • 我不认为Comparing positions is not possible with iterators 是正确的,你不能比较不同类型的迭代器,但来自同一个容器和相同类型的迭代器肯定是可比的
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-12-11
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多