如何使 find() 能够处理一组结构?

发布于 2024-11-04 17:29:22 字数 1405 浏览 4 评论 0原文

我正在使用 set 来保存包含多个字符串的结构。我希望能够使用集合的 find() 功能。但是,由于该集合保存结构,因此它不起作用。我希望 find() 只查看结构中的字符串之一。这怎么能做到呢?

这是我尝试使用的代码。除了使用 find() 的部分之外,它工作正常:

#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");
}

以下是我尝试编译它时收到的错误消息:

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.

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 only at one of the strings in the struct. 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 that I get 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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

狠疯拽 2024-11-11 17:29:22

我建议您将 operator<operator== 添加到您的结构中,而不是重载全局运算符,我发现它更干净;示例:

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;
  }
};

现在讨论您真正的问题 - 您将一个字符串传递给 find() 函数,但它只接受 test 类型的结构。为此,请添加一个用于自动转换的构造函数,因此最终的结构将如下所示:

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;
  }
};

然后将字符串传递给 find() 将自动调用构造函数并创建一个临时 test 结构仅包含相关键。请注意,在这种特殊情况下,构造函数不得显式声明。

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.

坏尐絯 2024-11-11 17:29:22

为了能够将结构放入 set 中,您必须为结构指定 operator< 。您可以使operator<返回比较相应字符串成员的结果。

为了能够使用find,您可以为结构指定operator==,以便在相应的字符串成员相等时返回true

示例:

    // 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);
}

如果您想使用 string 参数调用 find(),您可以为您的 teststring 提供隐式构造函数code> struct 例如这样:

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

但是使用隐式构造函数并不是一个好的技术,因为它可能会导致代码中更远的地方出现一些不可预测的转换。

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.

很酷不放纵 2024-11-11 17:29:22

首先,为了使 std::set::find () 与您的 struct 一起使用,您不需要指定 operator==,如 std::set:

[...] 两个对象 ab 如果两者都不小于另一个,则被认为是等效的: !comp(a, b) & & !comp(b, a).

但是,您的实际问题是,您无法在 C++14。在 C++14 之前,find() 需要一个元素作为参数,其类型与集合中存储的元素类型匹配。对于您的情况,这意味着您必须提供 test 的实例。但是,由于您的 operator< 仅比较 key 变量,因此您可以对 data 变量使用虚拟值,例如,如下所示:

test newmember;
newmember.key = "key";
newmember.data = "data";
s.insert(newmember);

auto it = s.find(test{ "key", "" });  // "" is the dummy variable.
std::cout << it->key << ", " << it->data << std::endl;

输出:

密钥、数据

请注意,仅比较 key 变量的 operator< 会产生副作用:只能存储 test 的两个实例如果它们的 key 变量不同,即使它们的 data 变量不同。例如,如果将以下代码附加到上面的代码中,则不会(再次)插入 newmember

newmember.data = "otherdata";
s.insert(newmember);  // Insertion fails!
for (auto const& t : s) {
    std::cout << t.key << ", " << t.data << std::endl;
}

输出:

密钥、数据

因此,如果您想存储具有相同键的多个元素,那么您可能必须选择不同的容器。

无论如何,如果一组 struct 适合您,并且您可以使用 C++11,那么你还可以使用 lambda表达式
而不是为您的 struct 定义 operator<

auto comp = [](const test& t1, const test& t2) { return t1.key < t2.key; };
std::set<test, decltype(comp)> s(comp);

Ideone 上的代码


C++14

C++14 开始,您可以使用 < code>find() 进行“透明比较”,如 std::set::find()
这意味着,您可以找到一个与给定参数等价的元素。
详细来说,这意味着您必须定义 operator< 和您的集合,如下所示:

bool operator<(const test& t, const std::string& str) { return t.key < str; }
bool operator<(const std::string& str, const test& t) { return str < t.key; }
bool operator<(const test& t1, const test& t2) { return t1.key < t2.key; }
std::set<test, std::less<>> s;

然后您可以按照您预期的方式执行 find() 操作:

test newmember;
newmember.key = "key";
newmember.data = "data";
s.insert(newmember);

auto it = s.find("key");
std::cout << it->key << ", " << it->data << std::endl;

输出:

密钥、数据

Ideone 上的代码

First and foremost, in order to make std::set::find() work with your struct, you don't need to specify operator==, as explained for std::set:

[...] two objects a and b are considered equivalent if neither compares less than the other: !comp(a, b) && !comp(b, a).

However, your actual problem is, that you can't search for parts of your struct by using find() prior to C++14. Prior to C++14, find() expects an element as argument, whose type matches the type of elements stored in the set. For your case, this means that you have to provide an instance of test. However, as your operator< compares only the key variables, you can use a dummy value for the data variable, for example, as follows:

test newmember;
newmember.key = "key";
newmember.data = "data";
s.insert(newmember);

auto it = s.find(test{ "key", "" });  // "" is the dummy variable.
std::cout << it->key << ", " << it->data << std::endl;

Output:

key, data

Please be aware that your operator< which compares only the key variables has a side effect: Two instances of test can only be stored in the set if their key variables are different, even if their data variables are different. For example, if you append the following code to the code above, then newmember will not be inserted (again):

newmember.data = "otherdata";
s.insert(newmember);  // Insertion fails!
for (auto const& t : s) {
    std::cout << t.key << ", " << t.data << std::endl;
}

Output:

key, data

Consequently, if you want to store multiple elements with the same key, then you might have to choose a different container.

Anyway, if a set of struct is fine for you and you can make use of C++11, then you can also use a lambda expression
instead of defining operator< for your struct:

auto comp = [](const test& t1, const test& t2) { return t1.key < t2.key; };
std::set<test, decltype(comp)> s(comp);

Code on Ideone


C++14

Since C++14, you can use find() to do a "transparent comparison" as explained on std::set::find().
This means, that you can find an element that compares equivalent to the given argument.
In detail this means, that you have to define operator< and your set as follows:

bool operator<(const test& t, const std::string& str) { return t.key < str; }
bool operator<(const std::string& str, const test& t) { return str < t.key; }
bool operator<(const test& t1, const test& t2) { return t1.key < t2.key; }
std::set<test, std::less<>> s;

Then you can perform your find() operation as you would have expected it to work:

test newmember;
newmember.key = "key";
newmember.data = "data";
s.insert(newmember);

auto it = s.find("key");
std::cout << it->key << ", " << it->data << std::endl;

Output:

key, data

Code on Ideone

那伤。 2024-11-11 17:29:22

只有你必须重写operator<()函数来增强查找功能。
在您的情况下,只需将运算符<()函数替换为..

bool operator<(const offer& t1) const {
    if(this->key< t1.key)
        return true;
    else if(this->key == t1.key){
         if(this->data < t1.data)
             return true;
         else
             return false;
    }
    else
        return false;
}

Only you have to override operator<() function to enhance find function.
In your case simply replace operator<() function as..

bool operator<(const offer& t1) const {
    if(this->key< t1.key)
        return true;
    else if(this->key == t1.key){
         if(this->data < t1.data)
             return true;
         else
             return false;
    }
    else
        return false;
}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文