2016-07-13 3 views
0

Я пытаюсь модифицировать два фрагмента устаревшего кода. Одна из частей реализует тайм-аут для вызова функции. До сих пор он использовался на C++-методах и отлично работает.Передача функций и параметров 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.

+0

Вы можете уменьшить код до keast, необходимый для генерации ошибки? Какую именно версию msvc вы используете? Нет ли других сообщений об ошибках? Обычно это дает контекст. – Yakk

+0

Компиляция с Clang в режиме C++ 11 или C++ 14. –

+0

@Yakk, извините, должно было быть более конкретным. Я использую Visual Studio 2015. – Amol

ответ

1

Проблема с станд :: поток, не принимающий packaged_task, std::thread(f, a...) работал нормально. Сейчас я бы не попробовать судоходства в водах std::thread (редактировать: где Андрей Р. предоставил хорошее объяснение в деталях, что пошло не так), в то время как 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 
} 
+0

Спасибо большое! Это очень помогло! – Amol

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(); 

или (лучше), чтобы следовать Аконкагуа решение

+1

Я рекомендую добавить std :: forward в первое решение. – Aconcagua

+0

Спасибо за объяснение. Это помогло мне понять, что происходит в этом коде, который я только что унаследовал. – Amol

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