2010-12-13 12 views
2

確定的な方法で反復処理したいポインタセットがあります。明らかに、setのデフォルトの並べ替え順序を使用すると、これはプログラムが実行されるたびに異なるポインタのメモリアドレスに基づいて行われます。だから私は使用したいカスタムコンパレータを定義しますが、テンプレートの型を変更する必要はありません(コードの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 ::少ない自体はテンプレートの特殊化を使用してカスタマイズすることである。

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のデフォルトのテンプレートコンパレータ::セットを使用して、カスタム動作を取得します。

システムの構築方法によっては、セットが「100万個所で使用」され、カスタムstd :: lessが一貫して利用できない場合に問題が発生する可能性があります。

+0

これは完璧です...しかし、あなたが1つのクラスにを設定して宣言すれば、それはカスタムlessを含まない別のクラスに渡されます - その第2のクラスは異なる/未定義の振る舞いを持つ可能性があります。私は、セットの定義とアクセサーメソッドのすべてがカスタムの少ない特殊化を含んでいることを確認します。 –

3

std::setコンプレッサオブジェクトの仮引数型はCompare const&です。Compareはテンプレートパラメータです。

したがって、(コピーする代わりに)実際のコンパレータオブジェクトへの参照が保持されていても、Compareとして扱われます。デフォルトはstd::lessです。

std::lessは非多型であるため、TestClassLessThanにはoperator()ではなく、std::less::operator()と呼ばれます。

だから、「それはできない」ということです。

コードが示すように、代わりに動作変更を行うことはできません。

比較オブジェクトを変更するには、他のCompareタイプをテンプレート引数として指定する必要があります。

これはあなたが避けたいものですが、申し訳ありませんが、(私が知っている)方法はありません。

乾杯& HTH。、コンパレータで設定し使用する方法ではありません

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

質問を読むと、私はセットの署名を変更したくないことに気付くでしょう。 –

関連する問題