3

を使用して、コレクションからsを作成するヘルパー関数(コレクション要素ごとに1つの未来)を使用std::asyncできるかどうか疑問に思いました。std::future

多くの場合、私は次の状況にあります。

auto func = []( decltype(collection)::reference value ) {
  //Some async work
};

typedef std::result_of<decltype(func)>::type ResultType;
std::vector<std::future<ResultType>> futures;
futures.reserve(collection.size());

// Create all futures
for( auto& element : collection ) {
  futures.push_back(std::async(func, element));
}

// Wait till futures are done
for( auto& future : futures ) {
  future.wait();
}

これを簡単に再利用できるようにするために、次の部分的なコードを考え出しました。

template< class Function, class CT, class... Args>
std::vector<std::future<typename std::result_of<Function(Args...)>::type>>
async_all( Function&& f, CT& col ) {

    typedef typename std::result_of<Function(Args...)>::type ResultType;
    std::vector<std::future<ResultType>> futures;
    futures.reserve(collection.size());

    for( auto& element : collection ) {
        futures.push_back(std::async(func, element));
    }
}
return futures;

で、もう推論できないので、今私はArgs問題を解決しなければなりません。私が現在考えることができるのは、コレクション内の要素をに変換する別のファンクターだけです。これに対するよりエレガントな解決策はありますか?async_allArgsArgs

4

1 に答える 1

3

あなたはほとんどそこにいます。渡されたコレクションにasync_allは、関数の引数の型を一意に決定するために必要なすべての情報が含まれています。唯一の問題は、この情報を抽出する方法です。関数シグネチャでキーワードを使用するautoと、関数の引数の後に戻り値の型を記述できます。これにより、より明確な署名が生成されるだけでなく、decltype戻り値の型を推測する際に引数値自体を使用することもできます。例えば:

template<typename F, typename CT>
auto reduce(F f, CT coll) -> decltype(f(*begin(coll), *begin(coll));

もちろん、提供された関数の引数の型を決定する方法は他にもあります (テンプレートでの関数シグネチャ推定を使用)。ただし、オーバーロードされた関数やテンプレート化された関数オブジェクトが関係する場合、これらのアプローチは失敗する可能性があります。

次のコードは、gcc 4.8 で適切にコンパイルおよび実行されます ("x=1" が 10 回出力されます) (以前のバージョンは問題なく動作するはずです)。明示的に言及する必要さえないことに注意してください。ステートメントでstd::future直接 decltype を使用して、そのstd::async型を推測できます。

#include <future>
#include <vector>
#include <iostream>

template<class Function, class CT>
auto async_all(Function f, CT col)
    -> std::vector<decltype(std::async(f, *std::begin(col)))>
{
    std::vector<decltype(std::async(f, *std::begin(col)))> futures;
    futures.reserve(col.size());

    for (auto& element : col) {
        futures.push_back(std::async(f, element));
    }
    return futures;
}

int main()
{
    using namespace std;
    for (auto& f : async_all([](int x) { cout << "x = " << x << endl; }, 
                             vector<int>(10, 1)))
       f.get();
}

(async_all仕様では範囲ベースの for ループでの範囲式が保証されているため、ここでは 1 回だけ評価されます)

于 2012-06-05T18:58:22.900 に答える