1

我有一个objectwith a property,这是该对象的方法所必需的:

class Object {
   Property property;
}

然后我需要对这个对象进行分组。要求在该组中只有具有唯一属性的对象。将这些对象分组是很自然的set。我定义 a operator<or 如果它是unordered_set operator==and hash()。没关系。然后另一个问题出现了。我需要使用property. 所以我需要创建一个类型的对象,Object并将这个属性分配给它的字段。这就是我不喜欢的地方。

另一种方法是制作一个map. 并复制或创建指向对象属性的指针,然后将它们用作映射中的键。我认为这也是一项双重工作。

我想要类似的东西set,但能够不使用整个对象进行搜索,而是使用对象的属性来查找它。例如,我定义以下内容:

class Object {
   Property property;
   bool operator<(Object obj) { return property < obj.property; }
   bool operator<(Property obj) { return property < obj.property; }
};
some::set<Object> objSet;

那么我可以执行以下操作:

Object obj;
objSet.insert(obj);
objSet.find(obj.property);

你能提供一些对我有帮助的容器实现吗?boost,qt 都可以接受。

4

3 回答 3

5

Boost Multi-Index 数组可能是您所需要的。此示例对单个集合进行多重排序与您正在寻找的内容非常匹配。

typedef multi_index_container<
  Object,
  indexed_by<
    ordered_unique<member<Object,Property,&Object::property> >
  > 
> object_set;

object_set oset;
Property prop;
oset.find( prop );
于 2013-02-28T21:08:02.330 回答
3

您可以使用std::equal_range的 4 参数重载,提供一个比较 aProperty和 an的比较器Object

struct Cmp
{
    bool operator() ( const Object& o, const Property& p ) const
    {
        return o.property < p;
    }
    bool operator() ( const Property& p, const Object& o ) const
    {
        return p < o.property;
    }
};

std::set<Object> s = ....;
Property property_val = ....;
auto r = std::equal_range(s.begin(),s.end(), property_val, Cmp());

另一种选择是使用std::find_if合适的一元谓词。但是您不会从std::setor的对数查找中受益std::equal_range

于 2013-02-28T20:50:46.553 回答
2

我会选择Boost Multi Index

如果值没有直接公开,您甚至可以根据需要从 Property 定义键提取器和索引。(为了便于打印,我将 Property 设为 struct 和 Object 公开,但只要 Property::get_value() 是公开的,这将起作用)

#include <iostream>
#include <string>
#include <algorithm>

#include <boost/multi_index_container.hpp>
#include <boost/multi_index/ordered_index.hpp>
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index/identity.hpp>
#include <boost/multi_index/member.hpp>
#include <boost/optional.hpp>

struct by_property_value{};
struct byseq{};
struct by_id{};

struct Property{
    int value;
    std::string name;

    int get_value() const{
        return value;
    }
};

class Object {
public:
   int id;
   Property property;
};

Object make_object(const int&id, const int& value, const std::string& name){
    Object res;
    res.id = id;
    Property p;
    p.value = value;
    p.name = name;
    res.property = p;
    return res;
}

bool operator<(const Object& lhs, const Object& rhs){
    return lhs.id < rhs.id;
}



using namespace boost;
using namespace boost::multi_index;

struct property_value_key_extractor{
    typedef int result_type;

    result_type operator()(const Object& o) const{
        return o.property.get_value();
    }
};

typedef multi_index_container<
    Object,
    indexed_by<
        sequenced<tag<byseq> >
        , ordered_unique<tag<by_id>,member<Object,int,&Object::id> >
        , ordered_non_unique<tag<by_property_value> , property_value_key_extractor >
    >
> Objects;


using namespace std;
int main(int argc, char *argv[]) {

    Objects objects;
    objects.push_back(make_object(1,1000,"a"));
    objects.push_back(make_object(2,200,"b"));
    objects.push_back(make_object(3,50,"c"));

    typedef Objects::index<by_property_value>::type objects_by_property_value;
    typedef objects_by_property_value::iterator property_value_iterator;

    property_value_iterator it = objects.get<by_property_value>().find(200);

    if(it != objects.get<by_property_value>().end()){
        cout << it->id << " " << it->property.get_value() << " " << it->property.name << endl;
    }

    cout << "Print by propety value" << endl;

    for(property_value_iterator it = objects.get<by_property_value>().begin(); it != objects.get<by_property_value>().end(); it++ ){
        cout << it->id << " " << it->property.get_value() << " " << it->property.name << endl;
    }

}

输出:

2 200 b
按财产价值打印
3 50 c
2 200 b
1 1000 a

于 2013-02-28T21:33:47.023 回答