0

いくつかの関数を考えてみましょう:

template<typename F>
void foo(F f) {
  std::unique_ptr<int> p = f();
  // do some stuff with p
}

unique_ptrはデフォルトのテンプレート引数 , default_deletefor を宣言するため、 に渡され、デフォルト以外のデリータでを返すD関数オブジェクトはコンパイルに失敗します。例えば、foounique_ptr

int x = 3;
foo([&x](){
    // use empty deleter
    return std::unique_ptr<int>(&x, [](int*){});
});

ただし、これが役立つ可能性があることはわかりましたが、それが不可能な直接的な理由はわかりません。これに対処するための一般的なアプローチはありますか?

編集

foo簡単な修正は、代わりに次を使用するように定義することです。

  std::unique_ptr<int, std::function<void(int*)>> p = f();

しかし、なぜこれを のインターフェースに組み込むことができなかったのunique_ptrでしょうか? クラス インターフェイスがこのジェネリック属性を提供できない理由はありますか? この種のものを新しい定義に「ラップ」するためのアプローチはありますか?

例えば、

template<typename T>
using Generic_unique_ptr =
  std::unique_ptr<
    T,
    std::function< void(typename std::unique_ptr<T>::element_type*) >
  >;

しかし、これは次のようなことを行う可能性があるため、危険に思えます。

Generic_unique_ptr<int> p(new int());

これにより、デリータが初期化されず、未定義の動作が示されます。おそらく、デフォルトのデリータとして のインスタンスを提供する方法はありますか? std::default_delete<T>

4

2 に答える 2

4

関数内でポインターを使用することだけが必要な場合は、autoキーワードを使用できます。コンパイラは、使用されている型を推測し、unique_ptr 自動的に正しいことを行います。

template <typename F>
void foo(F f)
{
    auto p = f();
    p->bar();
}

さて、あなたのコメントから、これがあなたが望むすべてではないことはわかっていますがunique_ptr、クラスに保存して後で操作できるようにしたいと考えています。これにより、一連のまったく異なる問題が発生します。

  1. unique_ptr<T, D1>unique_ptr<T, D2>、異なるタイプです。unique_ptr<T, D>したがって、ファンクタによって何が返されるかを知る必要がありますF
  2. の戻り値の型を事前に知っていたとしてもF、クラスは を保存することしかできず、unique_ptr<T, D1>を保存することはできませんunique_ptr<T, D2>

これを回避する最も簡単な方法 (私が考えることができる、より良い方法があるかもしれません) は、type eraseです。

によって管理されるポインターを公開する基本クラスを作成します unique_ptr

template <typename T>
struct wrapper
{
    virtual ~wrapper() {}
    virtual T const * get() const = 0;
    virtual T * get() = 0;
};

そのクラスから、次のタイプを推測する実際のストレージ クラスを継承しますunique_ptr

template <typename T, typename F>
struct storage
    : wrapper<T>
{
    storage(F f) { p_ = f(); }
    T const * get() const { return p_.get(); }
    T * get() { return p_.get(); }

    private:
        typename std::result_of<F()>::type p_;
};

実際に関心のあるクラスでは、基本クラスへのポインターを格納し、ポリモーフィズムを使用して基になるオブジェクト (この場合はunique_ptr. 上記のクラスを namespace detailユーザーから非表示にするために移動したとします。

template <typename T>
class some_class
{
    public:
        template <typename F>
        void store(F f)
        {
            storage_.reset(new detail::storage<T, F>(f));
        }

        T const * get() const { return storage_->get(); }
        T * get() { return storage_->get(); }

    private:
        std::unique_ptr<detail::wrapper<T>> storage_;
};

ここで完全に機能する例を見つけることができます。

于 2013-08-23T10:12:00.460 に答える