2013-02-14 40 views
10

在下面的示例代碼,我想從一個Component創建Item對象:從中間期貨創造未來?

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>


更新:刪除我的第一個想法(這是線程爲基礎)從問題和張貼答案。

+0

屬於上http://codereview.stackexchange.com? – 2013-02-14 14:30:32

+0

一個側面說明 - 更好地在Item的構造函數中使用const ref。 – 2013-02-14 14:31:27

+0

@LightnessRacesinOrbit它如何評論問題? 。他正在尋找更好的方法/方式! – M3taSpl0it 2013-02-14 14:31:41

回答

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()); 
    }); 
} 
+0

謝謝,這是我正在尋找的答案。我需要一種方法來有效地構建一個'std :: future'對象,但是線程的使用將是完全不必要的。 – 2014-01-17 19:14:27

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; 
}; 

一般來說,我建議忘記承諾並首先考慮packaged_tasks。 A packaged_task負責爲您維護一個(功能,承諾,未來)三聯。它允許你以自然的方式編寫函數(即使用返回和拋出等),並正確地將異常傳播到將來,這是你的例子忽略的(在你的程序中,未處理的異常在任何線程std::terminate!)。

+0

+1對於mo re代表 – 2013-02-14 14:41:16

+0

沒有更好的方法嗎?我想知道爲什麼還有另一個線程需要,如果所有的用戶正在嘗試隱藏一些內部實現並暴露一個更好的接口。 – balki 2013-02-15 12:22:24

+0

@balki不符合標準的東西。有計劃添加'future.then()',那就行了。 – 2013-02-15 12:34:27

2

您還可以使用Herb Sutter提出的then函數。這是一個稍微修改過的功能版本。有關它如何修改的更多信息以及與原始對話的鏈接可在this SO question中找到。您的代碼將歸結爲:

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

最初的想法是讓功能then作爲std::future<T>一個成員函數並有一些正在進行的將其放入標準的工作。該函數的第二個版本用於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; 
} 

上面的代碼編譯罰款鏗鏘或是libC++(在Mac OS X 10.8測試)。