10

次のサンプルコードでは、 :Itemからオブジェクトを作成します。Component

struct Component { };

struct Item {
    explicit Item(Component component) : comp(component) {}    
    Component comp;
};

struct Factory {
    static std::future<Item> get_item() {
        std::future<Component> component = get_component();        
        // how to get a std::future<Item> ?
    }

    std::future<Component> get_component();
};

std::future<Component>からに行くにはどうすればよいstd::future<Item>ですか?


更新:質問から私の最初のアイデア(スレッドベース)を削除し、回答を投稿しました。

4

3 に答える 3

13

moar packaged_tasksが必要です!

std::future<Item> get_item() {
    std::packaged_task<Item()> task([]{
        return Item(get_component().get());
    });
    auto future = task.get_future();
    std::thread(std::move(task)).detach();
    return future;
};

一般に、promiseを忘れて、最初にpackaged_tasksを検討することをお勧めします。Apackaged_taskは、(関数、promise、future)トリプルを維持します。これにより、関数を自然な方法で(つまり、リターンやスローなどを使用して)記述し、例外を将来に正しく伝播できます。これは、例では無視されていました(プログラムのどのスレッドでも未処理の例外std::terminateです!)。

于 2013-02-14T14:36:03.587 に答える
3

延期された起動ポリシーで使用std::asyncして、最終的なオブジェクトを作成できることに気づきました。

std::future<Item> get_item()
{
    // start async creation of component
    // (using shared_future to make it copyable)
    std::shared_future<Component> component = get_component();

    // deferred launch policy can be used for construction of the final object
    return std::async(std::launch::deferred, [=]() {
        return Item(component.get());
    });
}
于 2013-05-27T11:23:57.960 に答える
2

thenハーブサッターが提案する機能も利用できます。これは、関数のわずかに変更されたバージョンです。それがどのように変更されたか、および元の話へのリンクについての詳細は、このSOの質問にあります。コードは次のように要約されます。

return then(std::move(component), [](Component c) { return Item(c); });

元々のアイデアはthen、のメンバー関数としての機能を持つstd::future<T>ことであり、それを標準化するためのいくつかの進行中の作業があります。関数の2番目のバージョンは、void先物用です(基本的に関数を非同期にチェーンするだけです)。Herbが指摘したように、追加のスレッドが必要になる可能性があるため、このアプローチを使用することで料金を支払うことができます。

コードは次のようになります。

#include <future>
#include <thread>
#include <iostream>


template <typename T, typename Work>
auto then(std::future<T> f, Work w) -> std::future<decltype(w(f.get()))>
{
  return std::async([](std::future<T> f, Work w)
                    { return w(f.get()); }, std::move(f), std::move(w));
}

template <typename Work>
auto then(std::future<void> f, Work w) -> std::future<decltype(w())>
{
  return std::async([](std::future<void> f, Work w) -> decltype(w())
                    { f.wait(); return w(); }, std::move(f), std::move(w));
}

struct Component { };

struct Item {
  Item(Component component) : comp(component) {}
  Component comp;
};


struct Factory {
  static std::future<Item> get_item() {
    std::future<Component> component = get_component();
    return then(std::move(component), [](Component c) { return Item(c); });
  }

  static std::future<Component> get_component()
  {
    return std::async([](){ return Component(); });
  }

};

int main(int argc, char** argv)
{
  auto f = Factory::get_item();
  return 0;
}

上記のコードは、clangおよびlibc ++(Mac OS X 10.8でテスト済み)で正常にコンパイルされます。

于 2013-02-15T10:28:56.173 に答える