0

bi_map関連するキーと値のペアを両方向に格納するための単純な双方向マップ クラスの作業コードがあります。私の現在の使用法は、NIDある種の数値IDまたは列挙でOBJあり、高価なコピー不可能なクラスオブジェクトです。

最近、本当にコピーするだけの安価なものも必要bi_map<NID,std::string>であることに気付きました。std::stringOBJ

以下のコードを一般化して、適切な実装を使用できるように、ユーザーが何かが高価な (ポインター/参照を使用したい) か安価な (すべてを値でコピーしたい) かを通知できるようにする正しい方法は何ですか?

コード

template<typename NID,typename OBJ>
class bi_map
{
  std::map<NID,OBJ*>        m_nid_2_ptr;
  std::map<OBJ const*,NID>  m_ptr_2_nid;

public:
  void insert( NID nid, OBJ& obj )
  {
    m_nid_2_ptr.insert( std::make_pair( nid, &obj ));
    m_ptr_2_nid.insert( std::make_pair( &obj, nid ));
  }

  NID operator[]( OBJ const& obj ) const
  {
    return m_ptr_2_nid.at( &obj );
  }
  OBJ const& operator[]( NID nid ) const
  {
    return *(m_nid_2_ptr.at( nid ));
  }

  using pairs_cb = std::function<void(NID,OBJ const&)>;
  void pairs( pairs_cb cb ) const
  {
    for( const auto& p : m_nid_2_ptr )
      cb( p.first, *p.second );
  }
  size_t size() const { return m_nid_2_ptr.size(); }
};
4

2 に答える 2

5

一般に、複数の選択肢があり、正解は 1 つではないと思います。では、自分に合うものを探してみましょ。安価なタイプと高価なタイプを区別したいとおっしゃいましたね。最も重要な設計上の選択は、インターフェースです。あなたが使用することができます:

1)安価な型を使用しているインターフェイスに明示的な手がかりを持って、ポインターのテンプレートを特殊化します。

bi_map< int, std::string* > bi_map_1; // note * is to flag std::string as cheap
bi_map< int, ExpensiveObject > bi_map_2; // no *, thus using heavy implementation

これは次のように実装されています:

template< typename NID, typename OBJ >
struct bi_map
{
    // implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ>
};

// specialize of the second parameter is a pointer
template< typename NID, typename OBJ >
struct bi_map< NID, OBJ* >
{
    // implementation for cheap objects, store a copy, i.e., use OBJ
};

もちろん、より読みやすい場合は、型にフラグを立てる&代わりに使用することもできます。*

2)安価/高価な分離をインターフェイスに表示したくない場合、つまり、必要な場合

bi_map< int, std::string > bi_map_1; // no *
bi_map< int, ExpensiveObject > bi_map_2; // no *

何か違うものが必要です。1 つの解決策は、デフォルトのテンプレート パラメータを追加することです。

template< typename >
struct is_expensive_for_bi_map : std::false_type {};

template< typename IND, typename OBJ, bool = is_expensive_for_bi_map< OBJ >::value >
struct bi_map
{
    // implementation for expensive objects, use OBJ* or std::shared_ptr<OBJ>
};

template< typename NID, typename OBJ >
struct bi_map< NID, OBJ, false >
{
    // implementation for cheap objects, store a copy, i.e., use OBJ
};

そして、高価だと考えるタイプごとに、追加します

template<>
struct is_expensive_for_bi_map< ExpensiveObject > : std::true_type {};

高価ながデフォルトである必要がある場合は、名前を逆にして残りを適応させるだけで十分簡単です。

于 2013-04-01T19:31:49.617 に答える
0

別のオプション:

template<typename T>
struct notExpensive {
  static const bool value = FALSE;
  typedef T REF;
  static T& ref(T& x) { return x; }
  static T& deref(T& x) { return x; }
};
template<typename T>
struct isExpensive {
  static const bool value = TRUE;
  typedef T* REF;
  static T* ref(T& x) { return &x; }
  static T deref(T* x) { return x; }
};
template<typename T>
struct expensiveP : public notExpensive<T> {};

// List of expensive types:
template<> struct expensiveP<ExpensiveObject> : public isExpensive<T> {};

次に、biMap を高価な P 呼び出しで埋めます。

于 2013-04-01T23:42:52.060 に答える