3

スマートポインターラッパー(ブーストshared_ptrまたはscoped_ptrまたは別のスマートポインターラッパーを含む)を作成しようとしています。各ラッパータイプは、少し余分な機能(たとえば、ログの使用、遅延初期化、正しいコンストラクター/破棄順序の検証など)を注入しますが、ユーザーにはできるだけ見えないようにします(ラッパーをスワップイン/アウトできるようにします)。単一のtypedefを変更するだけで、場合によってはコンストラクターコードを変更するだけですが、使用法コードは変更しません)。

通常の使用法は簡単です。

template<typename T>
class some_smart_ptr_wrapper
{
public:
    typedef typename T::value_type value_type;
    ...
    value_type* get() { /*do something magic*/ return m_ptr.get(); }
    const value_type* get() const { /*do something magic*/ return m_ptr.get(); }
    // repeat for operator->, operator*, and other desired methods
private:
    T m_ptr;
};
typedef some_smart_ptr_wrapper< boost::shared_ptr<int> > smart_int;
smart_int p;

(これで、他のすべてのコードはp、少なくとも定義された操作では、shared_ptrと区別なく使用でき、typedefを変更するだけでラッパーを追加できます。)

複数のラッパーは、期待どおりにネストするだけで同時に使用でき、変数を宣言する(場合によっては初期化する)コードのみを処理する必要があります。

ラッパーから「基本的な」shared/scoped_ptrを取得できると便利な場合もあります(特に、ラッパーによって追加された機能をトリガーする必要のない関数への引数としてshared_ptrを渡す場合)。単一のラッパーレイヤーの場合、それは簡単です。

    T& getPtr() { return m_ptr; }
    const T& getPtr() const { return m_ptr; }

ただし、これは複数のラッパーレイヤーに適切にスケーリングされません(呼び出し元はp.getPtr().getPtr().getPtr()正しい回数を実行する必要があります)。

私ができるようにしたいのは、次のようにgetPtr()を宣言することです。

  • TがgetPtr()を実装している場合、m_ptr.getPtr()(どのタイプでも)を返します。
  • TがgetPtr()を実装していない場合は、m_ptrを返します。
  • ご想像のとおり、constフレーバーとnon-constフレーバーの両方で引き続き使用できます。

その結果、外部コードからgetPtr()を1回呼び出すだけで、元のスマートポインターへのチェーンが「ウォークアップ」されます。これは、getPtr()を実装しないのはそれだけだからです。

ソリューションにはSFINAEとboost::enable_ifが含まれると確信しています。私はそのようなものを機能させるために少し遊びましたが、これまでのところあまり運がありませんでした。

ソリューションまたは完全に代替のアプローチの両方を歓迎します。VC ++ 2008とGCCの両方で動作させたいことに注意してください(つまり、残念ながらC ++ 11はありません)。

4

3 に答える 3

1

(1)内部で一意の特別なメンバータイプ名を宣言します。

template<typename T>
class some_smart_ptr_wrapper
{
public:
  typedef T smart_type;  // <-- unique name
...
};

(2)getPtr()テンプレート関数ラッパー内にラップします。

template<typename T>
class some_smart_ptr_wrapper
{
...
public:
  T& getPtr () { return m_ptr; }

  typename My_sfinae<T>::RealType& getFinalPtr ()
  { return My_sfinae<T>::getPtr(m_ptr); }
...
};

(3)My_sfinae通常どおりに実装される場所:

template<typename T>
struct void_ { typedef void type; };

template<typename T, typename = void>
struct My_sfinae {
  typedef T RealType;

  static T& getPtr (T &p) { return p; }
};                        //^^^^^^^^^ business logic!
template<typename T>
struct My_sfinae<T, typename void_<typename T::smart_type>::type> {
  typedef typename My_sfinae<typename T::smart_type>::RealType RealType;

  static RealType& getPtr (T &p)
  { return My_sfinae<typename T::smart_type>::getPtr(p.getPtr()); }
};

ご覧のとおり、My_sfinaeすべてのラッパーを再帰的に削除すると、最後に最後のが残りますm_ptr

これがデモです。

于 2012-05-29T09:08:11.843 に答える
1

実際には、これは単純な問題です。オーバーロードを使用するだけです:)

template <typename T>
boost::scoped_ptr<T>& get_pointer(boost::scoped_ptr<T>& sp) { return sp; }

template <typename T>
boost::shared_ptr<T>& get_pointer(boost::shared_ptr<T>& sp) { return sp; }

// One overload per "wrapper"
template <typename T>
typename get_pointer_type<T>::type& get_pointer(some_wrapper<T>& p) {
    return get_pointer(p.getPtr());
}

get_pointer_typeその場合の秘訣は、ラッパーごとに正しく特化することです。

template <typename T>
struct get_pointer_type { typedef T type; };

template <typename T>
struct get_pointer_type< some_wrapper<T> > {
    typedef typename get_pointer_type<T>::type type;
};
于 2012-05-29T09:11:36.007 に答える
0

私の頭に浮かぶ最も近いものは、BjarneStroustrupによって書かれたWrappingC ++ MemberFunctionCallsという論文です。

このホワイトペーパーでは、プレフィックスコードとサフィックスコードのペアでオブジェクトへの呼び出しを「ラップ」するという古い問題に対する、シンプルで一般的かつ効率的なソリューションを紹介します。このソリューションは、邪魔にならず、既存のクラスに適用され、複数のプレフィックス/サフィックスのペアを使用でき、標準C++の15行の単純な行で実装できます。ラッパーの堅牢なバージョンも示されています。効率の主張は、測定によって裏付けられています。

于 2012-05-29T08:52:32.510 に答える