2010-12-13 71 views
2

我有一套指针,我想以确定的方式进行迭代。显然,如果我使用默认的排序顺序进行设置,这将基于指针的内存地址,每当程序运行时内存地址可能会不同。所以我定义了一个我想使用的自定义比较器,但我不想更改该集合的模板类型(因为它在代码中有100万个地方使用),所以我想将一个比较器对象传递给设置构造函数是从std :: less得到的自定义比较器通过显式构造函数进行排序std :: set

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

以上所有内容均有效。 一个可能的解决方案是的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 :: less不是一致可用的,你可能会遇到问题。

+0

这是完美的...但是你说如果我在一个类中声明了集,但是它被传递给另一个不包含该自定义的类 - 第二个类可能会有不同/未定义的行为?我想我会确保这个集合的定义和它的访问器方法都包含了非定制专业化。 – 2010-12-13 21:11:53

3

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

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

而且由于std::less是非多态是std::less::operator()被调用,而不是你的operator()下来TestClassLessThan

所以它的缺点是,“你不能这样做”。或者相反,你可以像你的代码所说明的那样,但是你不会有任何行为改变。

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

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

干杯&心连心,

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()); 
    } 
+1

如果你看过这个问题,你会注意到我不想改变这个集合的签名。 – 2010-12-13 03:28:22

相关问题