简体   繁体   English

将外部数据传递给 std::set 比较函子

[英]Passing external data to std::set Compare functor

This is a contrived example, I know it doesn't make sense in this context.这是一个人为的例子,我知道在这种情况下它没有意义。 In my real case, v contains a larger class, and I can't refactor v due to other dependencies in the code base.在我的实际情况中, v包含一个更大的类,由于代码库中的其他依赖关系,我无法重构v Also, in the real case I'm not using std::set but it simplifies the example.此外,在实际情况下,我没有使用std::set但它简化了示例。 Here are two example classes A and B that I know don't work, and I do understand why, but hopefully will illustrate what I'm trying to do:这是我知道不起作用的两个示例类AB ,我确实理解为什么,但希望能说明我正在尝试做的事情:

#include <set>
#include <vector>

using namespace std;

struct A
{
    A(initializer_list<float> init) : v(init)
    {
        for(size_t i = 0; i < init.size(); ++i)
        {
            s.insert(i);
        }
    }

    struct Less
    {
        Less(const vector<float>& v) : v(v) {};

        bool operator()(size_t i, size_t j)
        {
            return v[i] < v[j];
        }

        const vector<float>& v;
    };

    vector<float> v;
    set<size_t, Less> s;
};

struct B
{
    B(initializer_list<float> init) : v(init)
    {
        for(size_t i = 0; i < init.size(); ++i)
        {
            s.insert(i);
        }
    }

    template<const vector<float>& v>
    struct Less
    {
        bool operator()(size_t i, size_t j)
        {
            return v[i] < v[j];
        }
    };

    vector<float> v;
    set<size_t, Less<v>> s;
};

int main()
{
    A a = {1., 2., 3.};
    B b = {1., 2., 3.};
}

In both cases s contains indicies that refer to elements in v , and Less is trying to compare the values in v using those indices.在这两种情况下s包含引用v元素的索引, Less尝试使用这些索引比较v的值。 Is there a way to do this that I'm not seeing?有没有办法做到这一点,我没有看到?

Your A approach is almost correct.你的A方法几乎是正确的。 It just needs 2 fixes:它只需要 2 个修复:

  • bool operator()(size_t i, size_t j) should be const . bool operator()(size_t i, size_t j)应该是const
  • s must have a configured functor passed to it during construction. s必须在构造期间传递给它的已配置函子。
struct A
{
    A(initializer_list<float> init) : v(init), s(v)
    {
        for(size_t i = 0; i < init.size(); ++i)
        {
            s.insert(i);
        }
    }

    // These must be manually defined if you need them, the default
    // ones won't be correct.
    A(const A&) = delete; 
    A& operator=(const A&) = delete;

    struct MyLess
    {
        MyLess(const vector<float>& v) : v(v) {};

        bool operator()(size_t i, size_t j) const
        {
            return v[i] < v[j];
        }

        const vector<float>& v;
    };

    vector<float> v;
    set<size_t, MyLess> s;
};

I'm using unordered_map so maybe your idea will still work?我正在使用 unordered_map 所以也许你的想法仍然有效?

Yes, the same principle applies to std::unordered_set .是的,同样的原则适用于std::unordered_set You just have to pass in both hash and key_equal during construction.您只需要在构造过程中传入hashkey_equal Check out the documentation to identify the correct constructor to invoke.查看文档以确定要调用的正确构造函数。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM