【问题标题】:Compilation error with std::find when trying to fetch user defined objects from std::vector尝试从 std::vector 获取用户定义的对象时使用 std::find 的编译错误
【发布时间】:2019-08-10 07:51:41
【问题描述】:

我正在尝试创建一个模拟“便签”活动的基本应用程序。这将包含添加注释和删除注释的功能。下面是代码。在 deleteNote 函数中,我正在使用 std::find 方法作为输入参数给出的 Notes 向量中的标题。 std::find API 引发编译错误。下面是代码。

#include <iostream>
#include <vector>
#include <utility>
#include <tuple>
#include <algorithm>

using InitializerTags = std::initializer_list<std::string>;
using TupleObject = std::tuple<std::string, std::string, std::string>;

class Note
{
public:
    TupleObject m_tags;

    Note(std::string title, std::string text, std::string tags){
        std::cout<< "parameterized Constructor"<< std::endl;
        m_tags  =  std::make_tuple(title, text, tags);
    }

    /*Note(const Note& rhs){
        std:: cout << "copy constructor"<< std::endl;
        m_tags = rhs.m_tags;
    }*/

    Note(Note&& rhs){
        std::cout<< "move constructor"<< std::endl;
        m_tags = rhs.m_tags;
    }

    Note& operator=(Note&& rhs){
        std::cout << "move assignment"<< std::endl;
        if(this != &rhs){
            m_tags = rhs.m_tags;
        }
        return *this;
    }

    Note() = delete;
    Note(const Note& rhs) = delete;
    Note& operator=(const Note& rhs) = delete;

    ~Note(){

    }
};

class Storyboard
{
private:
    std::vector <Note> m_notes;
public:

    /*Storyboard(){
        m_notes.reserve(1);
    }*/

    void addNote(std::string title, std::string text, std::string tags)
    {
        std::cout << "inside addNote"<< std::endl;
        m_notes.emplace_back(title, text, tags);
    }

    void deleteNote(std::string title)
    {
        for(auto& x: m_notes){
            if(std::get<0>(x.m_tags) == title){
                m_notes.erase(std::find(m_notes.begin(),m_notes.end(), x));
            }
        }
    }


    void print()
    {
        std::cout << "Inside print"<< std::endl;
        for(auto& x : m_notes){
            std::cout << std::get<0>(x.m_tags)<< " ";
            std::cout << std::get<1>(x.m_tags)<< " ";
            std::cout << std::get<2>(x.m_tags)<< " ";
            std::cout << std::endl;
        }
    }
};

以下是错误。

在 /usr/include/c++/5/bits/stl_algobase.h:71:0 包含的文件中, 来自 /usr/include/c++/5/bits/char_traits.h:39, 从 /usr/include/c++/5/ios:40, 来自 /usr/include/c++/5/ostream:38, 来自 /usr/include/c++/5/iostream:39, 来自 StoryBoard.cpp:1: /usr/include/c++/5/bits/predefined_ops.h:在 'bool __gnu_cxx::__ops::_Iter_equals_val<_value>::operator()(_Iterator) 的实例化中 [with _Iterator = __gnu_cxx::__normal_iterator; _Value = const 注意]’: /usr/include/c++/5/bits/stl_algo.h:120:14: 来自 '_RandomAccessIterator std::__find_if(_RandomAccessIterator, _RandomAccessIterator, _Predicate, std::random_access_iterator_tag) [with _RandomAccessIterator = __gnu_cxx::__normal_iterator; _谓词 = __gnu_cxx::__ops::_Iter_equals_val]’ /usr/include/c++/5/bits/stl_algo.h:161:23: 来自 '_Iterator std::__find_if(_Iterator, _Iterator, _Predicate) [with _Iterator = __gnu_cxx::__normal_iterator; _谓词 = __gnu_cxx::__ops::_Iter_equals_val]’ /usr/include/c++/5/bits/stl_algo.h:3790:28: 需要从 '_IIter std::find(_IIter, _IIter, const _Tp&) [with _IIter = __gnu_cxx::__normal_iterator; _Tp = 注意]’ StoryBoard.cpp:67:73:从这里需要 /usr/include/c++/5/bits/predefined_ops.h:194:17: error: no match for ‘operator==’ (操作数类型是 ‘Note’ 和 ‘const Note’) { 返回 *__it == _M_value; }

我检查了发生错误的文件。

std::find 的签名出现了问题,它是 std::find(_IIter, _IIter, const _Tp&)

第 3 个输入参数被视为 const 引用,并将其与预定义_ops.h:194 中的非 const 引用进行比较。

我试图了解我的代码中导致这种情况的原因。

还试图找出解决办法。

任何有助于我理解的帮助将不胜感激。

【问题讨论】:

  • 这部分错误信息似乎是最相关的:“error: no match for 'operator==' (operand types are 'Note' and 'const Note')”简而言之,你无法比较两个 Note 对象是否相等

标签: c++11 vector


【解决方案1】:

std::find(m_notes.begin(),m_notes.end(), x)

std::find 算法尝试将来自m_notes 的元素与x 进行比较,但您没有提供operator== 来执行此操作,因此会出现错误消息。因为您正在根据标题擦除元素,所以您可以写:

class Note
{
public:
    //...

    // comparison operator as member function
    bool operator == (const Note& theOther) const {
        // compare titles
        return std::get<0>(m_tags) == std::get<0>(theOther.m_tags);
    }
    //...
};

然后代码编译,但可能会崩溃。 您正在使用基于范围的 for 循环来检查 vector::end 迭代器,但在调用 vector::erase 时它可能会失效。 See how range-for is implemented and how end is used.

现在您正在遍历 vector 中的所有元素,如果标题与 title 匹配,则您正在调用 find 来查找要删除的元素。这是矫枉过正,您可以使用迭代器遍历向量,当标题匹配时,只需为当前迭代器调用erase 算法,而无需通过find 重新迭代向量:

deleteNote 改写成这样的:

void deleteNote(std::string title)
{
    for (auto it = m_notes.begin(); it != m_notes.end(); )
    {
        if(std::get<0>(it->m_tags) == title)
            it = m_notes.erase(it); // returns the first element past the removed one
        else 
            ++it;
    }
}

如果您想在移动 ctor 和移动赋值运算符中移动 rhs.m_tags;,您需要将 rhs.m_tags 转换为 Rreference - m_tags = std::move(rhs.m_tags);

【讨论】:

  • @ 一些程序员老兄和@rafix07 非常感谢提供的输入。
猜你喜欢
  • 2013-05-08
  • 2015-01-04
  • 2022-12-07
  • 2023-02-16
  • 1970-01-01
  • 2015-10-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多