自定义比较器通过显式构造函数对std :: set进行排序

时间:2010-12-13 01:37:27

标签: c++ sorting set

我有一组指针,我想以确定的方式迭代。显然,如果我使用set的默认排序顺序,这将基于指针内存地址,每次程序运行时它们可能不同。所以我定义了一个我想要使用的自定义比较器,但是我不想更改集合的模板化类型(因为它在代码中的一百万个位置使用),所以我想将一个比较器对象传递给设置从std :: less

派生的构造函数
class TestClass
{
public:
    TestClass(int id_) : id(id_)    {}
    ~TestClass()                    {}
    int  getId() const              { return id;}
    void setId(int id_)             { id = id_; }
private: 
    int id; 
};

struct TestClassLessThan : public std::less<TestClass*>
{   // functor for operator<
    bool operator()(const TestClass* &_Left, const TestClass* &_Right) const
    {   // apply operator< to operands
        return (_Left->getId() < _Right->getId());
    }
};


int main(void)
{
    TestClassLessThan comp; 
    set<TestClass*> testSet(comp), testSet2(comp);

    TestClass* obj1 = new TestClass(1);
    TestClass* obj2 = new TestClass(2);
    testSet.insert(obj1);
    testSet.insert(obj2);

    TestClass* obj = *(testSet.begin());

    cout << "First run" << endl;
    BOOST_FOREACH(TestClass* o, testSet)  // expecting 1,2 - get 1,2
        cout << o->getId() << endl;

    // now change the ordering (based on id) and insert into a new set in the same order
    obj1->setId(3);
    testSet2.insert(obj1);
    testSet2.insert(obj2);

    cout << "Second run" << endl;
    BOOST_FOREACH(TestClass* o, testSet2) // expecting 2,3 - get 3,2
        cout << o->getId() << endl;

    delete obj1;
    delete obj2;
}

所以我的问题是,我忘了做什么?

3 个答案:

答案 0 :(得分:3)

比较器对象的std::set构造函数的形式参数类型为Compare const&,其中Compare是模板参数。

因此,即使set对象保留了对实际比较器对象的引用(而不是复制它),它也会被视为类型Compare,您默认为std::less

由于std::less是非多态的,所以std::less::operator()被调用,而不是operator() TestClassLessThan {。}}。

所以缺点是,“你做不到”。

或者更确切地说,您可以像代码所示,但不会改变任何行为。

要更改比较对象,您必须将其他Compare类型指定为模板参数。

这是你想要避免的,但对不起,没有办法(我知道)。

干杯&amp;第h。,

答案 1 :(得分:3)

以上所有内容均有效。 一种可能的解决方案是使用模板特化来自定义std :: less本身:

namespace std
{
    template<>
    struct less< TestClass*>
    {   // functor for operator<
    public:
        bool operator()(  TestClass* const  &_Left,  TestClass* const  &_Right) const
        {   // apply operator< to operands      
            return (_Left->getId() < _Right->getId());
        }
    };
}

然后使用std :: set的默认模板比较器获取自定义行为。

根据您构建系统的方式,如果该集合“在一百万个地方使用”并且自定义std :: less不能始终可用,则可能会出现问题。

答案 2 :(得分:1)

这不是使用比较器设置的方法。 std :: less的operator()不是虚函数,不会被覆盖。

而是使用这种方式进行初始化,它就可以解决问题。

set<TestClass*, TestClassLessThan> testSet, testSet2;

为此,比较函数应该接受const指针而不是指向const的指针。为了安全起见,您可以将其更改为

 // functor for operator<
    bool operator()(const TestClass* const&_Left, const TestClass* const&_Right) const
    {   
        cout << "comparing";
        // apply operator< to operands
        return (_Left->getId() < _Right->getId());
    }