将C函数和参数作为右值引用传递

时间:2016-07-13 02:44:14

标签: c++ windows visual-studio templates c++11

我试图改造两段遗留代码。其中一个部分实现了函数调用的超时。到目前为止,它已被用于C ++方法并且运行良好。

现在,要求对旧版C库实施类似的超时。我尝试使用相同的代码,但遇到了问题。

这是代码的简化版本,我面临的问题就在这里。

uint32_t myFunc1()
{
    return 0;
}

uint32_t myFunc2(uint32_t a)
{
    return a;
}

int main()
{
    uint32_t dummy = 1;
    timedCall(myFunc1); //compiles fine. 
    timedCall(myFunc2, dummy); //compile errors C2672, C2893
}

template <class F, class... Args>
uint32_t timedCall(F &&f, Args&&... a)
{
    try
    {
        std::packaged_task<uint32_t(Args...)> myTask(std::bind(f, a...));
        auto res = myTask.get_future();
        std::thread(std::move(myTask), a...).detach(); //This is where the issue is.        

        //Do other stuff
    }
    catch(...)
    {
        //handle exceptions
    }

    return 0; //return something
}

我收到以下错误:

C2672   'std::invoke': no matching overloaded function found
C2893   Failed to specialize function template 'unknown-type std::invoke(_Callable &&,_Types &&...)'

有人可以告诉我我做错了什么以及如何解决这个问题?我正在使用Visual Studio 2015.

2 个答案:

答案 0 :(得分:1)

当您使用std::bind(f, a...)时,您将获得可以使用obj()调用的可调用对象。但是std::packaged_task<uint32_t(Args...)>的构造函数需要使用obj(a...)来调用对象。但是,有些编译器可能会忽略额外的参数。

您需要删除bind

std::packaged_task<uint32_t(Args...)> myTask(f);
auto res = myTask.get_future();
std::thread(std::move(myTask), std::forward<Args>(a)...).detach();

或者更改调用语法:

std::packaged_task<uint32_t()> myTask(std::bind(f, std::forward<Args>(a)...));
auto res = myTask.get_future();
std::thread(std::move(myTask)).detach();

或(更好)遵循Aconcagua解决方案

答案 1 :(得分:1)

问题是std :: thread不接受packaged_task,std::thread(f, a...)工作正常。现在我不会尝试在std::thread水域发货(编辑:,其中Andrei R.详细解释了哪里出了问题),而std::async将使任务变得更容易为你:

template <class F, class... Args>
uint32_t timedCall(F &&f, Args&&... a)
{
    try
    {
        auto res = std::async
        (
            std::launch::async,
            std::forward<F>(f),
            std::forward<Args>(a)...
        );
        //Do other stuff
    }
    catch(...)
    {
        //handle exceptions
    }

    return 0; //return something
}