2016-10-18 21 views
0

次の構造:次の状況でセット挿入はどのように機能しますか?

struct SomeStructure { 
     uint64_t value; 
     uint64_t data; 
}; 

bool operator > (const SomeStructure& v1, const SomeStructure& v2) { 
     return (v1.value > v2.value); 
} 
bool operator < (const SomeStructure& v1, const SomeStructure& v2) { 
     return (v1.value < v2.value); 
} 
bool operator == (const SomeStructure& v1, const SomeStructure& v2) { 
     return (v1.value == v2.value); 
} 

は、次のようなコードで使用されます。

SomeStructure st1, st2; 
st1.value = st2.value = 10; // has the same 'value' 
st1.data = 20; // but is assigned a different number for the 'data'. 
st2.data = 40; 

std::set<SomeStructure> TheSet; 
TheSet.insert(st1); 
TheSet.insert(st2); 

st1st2を挿入しますセットに存在する要素の値を置き換えますか?オペレータ><のみメンバーSomeStructure::valueに依存するようにオーバーロードされているため、TheSetにそれらを挿入しながら、上記の例では

は、st2st1両方が同じであると考えられます。しかし、これらのオブジェクトではSomeStructure::dataの値が異なります。したがって、それはTheSetの既存の要素を置き換えますか、または要素が既に存在する場合は挿入操作を無視しますか?

これらの2つの動作のどちらかを明示的に実施する方法はありますか?

この動作はコンパイラとプラットフォームによって変わりますか?

編集1:

私はちょうどグラムでこれをテストした++コンパイラ(C++ 11を有効にしました)。それは置き換えません。既存の要素を置き換えるためにこれを明示的に実施する方法はありますか?

編集2:

実際には、この動作を「強制」する標準的な方法はありませんが、それはを通じて、単純なハックを使用して行うことができます。このメソッドは推奨されませんが、私はここにそれを提示してみましょう:

この方法は、STD ::設定

template <typename T> 
void insert_replace(std::set <T>& theSet, const T& toInsert) { 
     auto it = theSet.find(toInsert); 
     if(it != theSet.end()) 
     *((T*)&(*it)) = toInsert; 
     else 
      theSet.insert(toInsert); 
} 

内のメンバ関数insertの代わりに使用する必要があり、上記のコードでなければなりません置き換え:

int main() { 

    SomeStructure st1, st2; 
    st1.value = st2.value = 10; // has the same 'value' 
    st1.data = 20; // but is assigned a different number for the 'data'. 
    st2.data = 40; 


    std::set<SomeStructure> TheSet; 

    insert_replace (TheSet, st1); 
    insert_replace (TheSet, st2); 


    for(auto ii : TheSet) { 
     std::cout << ii.data; 
    } 
    return (0); 
} 

この方法では、出力を与え、私のコンパイラで正常に動作します:40、代わりの20。しかし、私は人々がこれは推奨された方法ではないと思うかもしれないと考えています。なぜなら、*((T*)&(*it)) = toInsert;という行は、イテレータitが定数ではないと考えてコンパイラを欺くものです。私はこれが唯一の方法であると信じて、交換することによって、std::setを挿入することができます。私のコードでこのメソッドを使うのはいいですか?将来(たとえ私がそれを文書化しても)問題を引き起こしますか?documentationから

+1

フレンドリーマニュアルを読んでいますか? –

+1

両方を挿入したい場合は、比較関数を変更して、 'value'と' data'の両方をチェックします。それ以外の場合は無視されます。 – Barmar

+0

実際には、 'value'のみに依存することになっています。私のコードでは、既存の要素を新しい要素に置き換える必要があります。しかし、標準の動作の一部ですか?それともコンパイラで変わるのだろうか? –

答えて

1

挿入動作チェックは、各挿入素子は、既に容器の要素と同等であるかどうか、そしてもしそうであれば、要素が挿入されていない

だからTheSet.insert(st2);意志st2は既にセットに含まれているst1と等しいため、何も挿入しないでください。

両方を挿入できるようにするには、比較機能を変更してvaluedataの両方をテストするか、またはstd::multisetを使用して重複したエントリを許可する必要があります。

+0

ありがとうございます。実際には、私は故意にそれを「価値」だけに依存させました。 'st2'が挿入されたときに' st1'を置き換えるようにしたいと思います。今私は、この種のタスクのoptデータ構造が 'std :: set'ではなく' std :: map'であると考えています。 –

関連する問題