2012-06-05 2 views
3

Использование std::async Мне было интересно, возможно ли иметь вспомогательную функцию, которая создает std::future из коллекции (одно будущее для каждого элемента коллекции).std :: async вариант, который работает над коллекцией

Часто у меня следующая ситуация:

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_all, Args больше не может быть выведено. Единственное, о чем я сейчас думаю, это еще один функтор, который преобразует элемент в коллекции в Args. Есть ли еще более элегантное решение?

ответ

3

Вы почти у цели. В коллекции, прошедшей до async_all, имеется вся информация, необходимая для однозначного определения типа аргумента функции; единственный вопрос - как извлечь эту информацию. Используя ключевое слово auto в сигнатуре функции, мы можем написать тип возвращаемого значения после аргументов функции. Это не только дает более чистую подпись, но также позволяет использовать сами значения аргументов вместе с decltype при выводе типов возврата. Например:

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

Конечно, есть и другие способы определения типов аргументов для предоставленных функций (с помощью функции подписи дедукции с шаблонами). Тем не менее, эти подходы могут быть неудачными для случаев, связанных с перегруженными функциями и/или шаблонами функций.

Следующий код компилируется и работает правильно (печатает «x = 1» 10 раз) под gcc 4.8 (более ранние версии должны работать нормально). Обратите внимание, что нам даже не нужно явно указывать 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 оценивается только один раз здесь, как спецификации гарантий для выражения дальности в диапазоне на основе для петель)

Смежные вопросы