je tente de mettre en œuvre std::async
à partir de zéro, et se sont heurtées à un accident de parcours avec des arguments de type de mouvement uniquement. L'essentiel est, C++ 14 init-captures nous permettent de capturer des variables simples "par déplacement" ou "par transfert parfait", mais ils ne semblent pas apparaissent pour nous permettre de capturer paquets de paramètres "par déplacement" ni "par transfert parfait", car vous ne pouvez pas capturer un pack de paramètres par init-capture - uniquement par capture nommée.En utilisant std :: bind pour capturer un pack de paramètres « par mouvement »
J'ai trouvé ce qui semble être une solution de contournement, en utilisant std::bind
pour capturer le pack de paramètres « par mouvement », puis en utilisant une enveloppe pour déplacer les paramètres de la mémoire de l'objet de liaison dans les fentes des paramètres de la fonction Je veux vraiment appeler. Il semble même élégant, si vous ne pensez pas trop à ce sujet. Mais je ne peux pas m'empêcher de penser qu'il doit y avoir un meilleur moyen - idéalement celui qui ne compte pas sur std::bind
du tout.
(Dans le pire des cas, j'aimerais savoir combien de std::bind
je devrais réimplémenter par moi-même pour m'en éloigner.) L'un des objectifs de cet exercice est de montrer comment tout est mis en œuvre. le chemin vers le bas, afin d'avoir une dépendance aussi compliquée que std::bind
vraiment nul)
Mes questions sont les suivantes:.
Comment puis-je faire mon travail de code, sans utiliser
std::bind
? (Par exemple, en utilisant uniquement des caractéristiques linguistiques essentielles. Lambdas génériques sont un jeu équitable.)est mon pare-balles
std::bind
solution de contournement? Autrement dit, quelqu'un peut-il montrer un exemple où lestd::async
du STL fonctionne et monAsync
échoue?Pointeurs à la discussion et/ou des propositions pour soutenir la capture paramètre-pack en C++ 1Z sera accepté avec reconnaissance.
template<typename UniqueFunctionVoidVoid>
auto FireAndForget(UniqueFunctionVoidVoid&& uf)
{
std::thread(std::forward<UniqueFunctionVoidVoid>(uf)).detach();
}
template<typename Func, typename... Args>
auto Async(Func func, Args... args)
-> std::future<decltype(func(std::move(args)...))>
{
using R = decltype(func(std::move(args)...));
std::packaged_task<R(Args...)> task(std::move(func));
std::future<R> result = task.get_future();
#ifdef FAIL
// sadly this syntax is not supported
auto bound = [task = std::move(task), args = std::move(args)...]() { task(std::move(args)...) };
#else
// this appears to work
auto wrapper = [](std::packaged_task<R(Args...)>& task, Args&... args) { task(std::move(args)...); };
auto bound = std::bind(wrapper, std::move(task), std::move(args)...);
#endif
FireAndForget(std::move(bound));
return result;
}
int main()
{
auto f3 = [x = std::unique_ptr<int>{}](std::unique_ptr<int> y) -> bool { sleep(2); return x == y; };
std::future<bool> r3 = Async(std::move(f3), std::unique_ptr<int>{});
std::future<bool> r4 = Async(std::move(f3), std::unique_ptr<int>(new int));
assert(r3.get() == true);
assert(r4.get() == false);
}
vous devriez préférer rediriger les références avec 'std :: forward' pour prendre les paramètres par valeur et utiliser' std :: move' –
Les tuples peuvent vous donner beaucoup de latitude lorsqu'il s'agit de stocker des paquets de choses (contraste 'std: : tie', 'std :: make_tuple',' std :: forward_as_tuple' ou en utilisant un constructeur directement) et quand il s'agit de 'restaurer' les éléments du pack original. D'un autre côté, cela soulève la question de savoir comment implémenter un tuple assez facilement à des fins didactiques et/ou comment «développer» des éléments de tuple dans un appel. Est-ce que le fait de prendre 'std :: tuple' pour acquis empêcherait une réponse d'être utile? –
@PiotrS Je ne crois pas qu'il soit * possible * d'implémenter 'async' sans capturer les arguments par valeur. Sinon, vous finissez avec des références qui pendent au moment où vous vous déplacez pour exécuter la tâche.(N'hésitez pas à me prouver le contraire en écrivant du code dans une réponse!) @LucDanton bien sûr, je suis heureux d'utiliser 'tuple' dans une solution, mais je ne sais pas comment" développer des éléments de tuple dans un appel "sans beaucoup de lignes de code, même en C++ 14. – Quuxplusone