包装到std :: async()不起作用

时间:2016-12-13 15:20:39

标签: c++ c++11

编辑:对std :: bind()的调用可以用其他东西替换,我只是想让runAsyncTerminateOnException()使用与std :: async()相同的签名,就像它只是一个包装器

我正在尝试为std :: async()创建一个包装器。 当你直接调用std :: async()时,你知道如何让包装器工作吗?

注意:我不会修改print()函数签名,这是一个例子。我希望包装器是通用的,并且可以通过直接调用std :: async()来处理所有可能的参数。

谢谢。

http://ideone.com/HbBqeo

#include <iostream>
#include <functional>
#include <future>

template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
    auto make_call = std::bind(std::forward<Fn>(fn), std::forward<Args>(args)...);

    return std::async(std::launch::async, [=]() -> decltype(make_call()) {
        try {
            return make_call();
        } catch (...) {
            std::cout << "Terminate Called!" << std::endl;
            std::terminate();
        }
    });
}

struct Foo {
    template<class... Args>
    void print(Args&&... args) {
        printf("Foo::print(%d)\n", std::forward<Args>(args)...);
    }
};

int main() {
    Foo foo;
    std::future<void> future = std::async(std::launch::async, &Foo::print<int>, &foo, 2);
    std::future<void> future2 = runAsyncTerminateOnException(&Foo::print<int>, &foo, 2);
    // your code goes here
    return 0;
}

2 个答案:

答案 0 :(得分:2)

您需要按如下方式更改runAsyncTerminateOnException来电:

std::future<void> future2 = 
    runAsyncTerminateOnException(&Foo::print<const int&>, &foo, 2);

这是由于an unfortunate interaction between std::bind, variadic templates and perfect forwarding

我建议您使用lambdas,它几乎总是优于std::bind(有关详情,请参阅STL的this talk。)

template<class Fn>
inline auto runAsyncTerminateOnException(Fn&& fn) 
{    
    return std::async(std::launch::async, [=]() -> decltype(fn()) {
        try {
            return fn();
        } catch (...) {
            std::cout << "Terminate Called!" << std::endl;
            std::terminate();
        }
    });
}

(请注意,我正在将fn复制到lambda中 - 如果您想要更正确和通用的解决方案,则应考虑perfect-forward capturing the object into the lambda。)

std::future<void> future2 = 
    runAsyncTerminateOnException([&foo]{ return foo.print(2); });

wandbox example

答案 1 :(得分:0)

我找到了c ++ 17的解决方案。 仅当我们不为runTerminateOnException()的返回类型使用auto时,它才有效。

template<class Fn, class... Args>
inline std::result_of_t<Fn&&(Args&&...)> runTerminateOnException(Fn&& fn, Args&&... args) {
    try {
        return std::invoke(std::forward<Fn>(fn), std::forward<Args>(args)...);
    } catch (...) {
        std::terminate();
    }
}

template<class Fn, class... Args>
inline auto runAsyncTerminateOnException(Fn&& fn, Args&&... args) {
    return std::async(std::launch::async, runTerminateOnException<Fn, Args&&...>, std::forward<Fn>(fn), std::forward<Args>(args)...);
}