多数のメンバーを持つ構造体があり、次のように、メンバーの 1 つを介して参照される特定の値をセットのキーとして使用したいとします。
class ComplexClass {
public:
const string& name() const;
// tons of other stuff
};
struct MyStruct {
ComplexClass* c;
MoreStuff* x;
};
struct CmpMyStruct {
bool operator()(const MyStruct& lhs, const MyStruct& rhs) {
return lhs.c->name() < rhs.c->name();
}
};
typedef set<MyStruct, CmpMyStruct> MySet;
MySet my_set;
これは問題なく動作しますが、今度は文字列 nameでルックアップを行いたいのですが、my_set.find() はもちろん「const MyStruct&」を使用します。その名前がその ComplexClass から取り出されたのではなく、代わりに MyStruct のメンバーである場合、MyStruct のインスタンスをすぐに偽造してそれを使用することができます。
MyStruct tmp_for_lookup;
tmp_for_lookup.name = "name_to_search"; // Doesn't work of course
MySet::iterator iter = my_set.find(tmp_for_lookup);
ただし、前述のように、それは機能する方法ではありません。名前はComplexClassにあるため、少なくともそのモックをそこに置く必要があります。
したがって、私が実際に望んでいるのは、STL セットが MyStructs を比較するのではなく、まず MyStruct (文字列型) からキーを「投影」してから、find() を含むその操作を実行することです。私は、gcc での set/map の実装を掘り下げて、マップの問題をどのように解決したかを調べ始めました。内部の _Rb_tree で実際に解決したことを見て悲しくなりましたが、公開していませんでした。標準。gcc の stl_tree.h から:
template<typename _Key, typename _Val, typename _KeyOfValue,
typename _Compare, typename _Alloc = allocator<_Val> >
class _Rb_tree
{
....
template<typename _Key, typename _Val, typename _KeyOfValue,
typename _Compare, typename _Alloc>
typename _Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::iterator
_Rb_tree<_Key, _Val, _KeyOfValue, _Compare, _Alloc>::
find(const _Key& __k)
そして、stl_map.h で:
typedef _Rb_tree<key_type, value_type, _Select1st<value_type>,
key_compare, _Pair_alloc_type> _Rep_type;
'_Select1st' を使用して value_type からキーを投影する方法に注意してください。したがって、find() は実際にはキーを操作できます。一方、 stl_set.h は、その場合、予想どおり Identity を使用するだけです。
したがって、通常のSTLセット/マップで同じ美しさと効率を実現する方法について、現在欠けている方法はありますか(つまり、GCC固有の_Rb_treeを直接使用したくありません)、私が本当にできるように
MySet::iterator iter = my_set.find("somestring");
特に、my_set を文字列から MyStructs へのマップに変更したくないことに注意してください。つまり、文字列 (またはその参照) を ComplexClass からコピーしたくないので、代わりにmap<string, MyStruct>
orを実行できますmap<const string&, MyStruct>
。
これは、この時点ではほとんど思考演習ですが、興味深いように思えました :)