Making find work with a set of structs

2019-03-20 06:17发布

I am using a set to hold structs which contain several strings. I want to be able to use the find() functionality of sets. However, since the set is holding structs, it doesn't work. I want find() to look at one of the strings in the struct when it does find. How can this be done?

Here's the code that I tried to use. It works fine except for the part where find() is used.

#include <iostream>
#include <string>
#include <set>
using namespace std;

struct test
{
    string key;
    string data;
};

bool operator<(const test & l, const test & r)
{
    return l.key < r.key;
}

bool operator==(const test & l, const test & r)
{
    return l.key == r.key;
}

set<test> s;

int main()
{
    test newmember;
    newmember.key = "key";
    newmember.data = "data";
    s.insert(newmember);
    s.find("key");
}

Here are the error messages when I try to compile it:

test.cpp:30:7: error: no matching member function for call to 'find'
    s.find("key");
    ~~^~~~
In file included from test.cpp:3:
In file included from /usr/include/c++/4.2.1/set:65:
/usr/include/c++/4.2.1/bits/stl_set.h:429:7: note: candidate function not viable: no known conversion from 'const char [4]' to 'const key_type' (aka 'const test') for 1st argument
      find(const key_type& __x)
      ^
/usr/include/c++/4.2.1/bits/stl_set.h:433:7: note: candidate function not viable: no known conversion from 'const char [4]' to 'const key_type' (aka 'const test') for 1st argument
      find(const key_type& __x) const
      ^
1 error generated.

标签: c++ struct set
3条回答
何必那么认真
2楼-- · 2019-03-20 06:52

To be able to put your structs into set you have to specify operator< for your struct. You can make the operator< return result from comparing corresponding string members.

To be able to use find you can specify operator== for your struct to return true if corresponding string members are equal.

Sample:

    // code from your question used here

    int main()

{
    test newmember;
    newmember.key = "key";
    newmember.data = "data";

    test findMember;
    findMember.key = "key";
    // as operator== and operator< doesn't care about data field we can left it be
    // initialized by default constructor

    s.insert(newmember);
    s.find(findMember);
}

If you want to call find() with string parameter you can provide an implicit constructor from string for your test struct for example like this:

struct test {
//...
  test(const string &in_key) : key(in_key) {}
//...
};

But usage of implicit constructors isn't a good technique, because it can lead to some unpredictable conversions somewhere further in your code.

查看更多
萌系小妹纸
3楼-- · 2019-03-20 07:09

Refer this link : find_if using vectorlist

This link will use to find the element in the vector or template list.

查看更多
狗以群分
4楼-- · 2019-03-20 07:13

I suggest you operator< and operator== to your struct instead of overloading the global operator, I find it much cleaner; example:

struct test
{
  string key;
  string data;

  bool operator<(const test& rhs) const
  {
    return key < rhs.key;
  }

  bool operator==(const test& rhs) const
  {
    return key == rhs.key;
  }
};

Now on to your real problem - your are passing a string to the find() function, but it only accepts structs of type test. In order to do so, add a constructor for automatic conversion, so the final struct would look like this:

struct test
{      
  string key;
  string data;

  test(const std::string& strKey = "", const std::string& strData = "")
  : key(strKey),
    data(strData) {}

  bool operator<(const test& rhs) const
  {
    return key < rhs.key;
  }

  bool operator==(const test& rhs) const
  {
    return key == rhs.key;
  }
};

Then passing a string to find() would automatically call the constructor and create a temporary test struct containing only the relevant key. Note that in this special case, the constructor must not be declared explicit.

查看更多
登录 后发表回答