2014-03-28 5 views
3

std :: package_task 및 std :: thread를 사용하여 std :: async를 에뮬레이트 한 Antony Williams - C++ Concurrency in Action 예제 4.14를 사용하여 연주하고 있습니다.packaged_task가있는 템플릿이 컴파일되지 않았습니다

줄을 주석 처리 할 때이 코드가 컴파일되지 않고 왜 작동하도록하려면이 코드를 다시 작성해야합니까?

#include <iostream> 
#include <future> 
#include <thread> 
#include <string> 

void func_string(const std::string &x) {} 

void func_int(int x) {} 

template <typename F, typename A> 
std::future<typename std::result_of<F(A&&)>::type> spawn_task(F &&f, A &&a) { 
    typedef typename std::result_of<F(A&&)>::type result_type; 
    std::packaged_task<result_type(A&&)> task(std::move(f)); 
    std::future<result_type> res(task.get_future()); 
    std::thread t(std::move(task), std::move(a)); 
    t.detach(); 
    return res; 
} 


int main() { 
    std::string str = "abc"; 

    // auto res1 = spawn_task(func_string, str); 
    // res1.get(); 
    auto res2 = spawn_task(func_int, 10); 
    res2.get(); 

    return 0; 
} 

컴파일 오류 모든 std::packaged_task

[email protected] /tmp $ clang++ -std=c++11 -lpthread temp.cpp && ./a.out 
In file included from temp.cpp:2: 
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/future:38: 
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1697:56: error: no type 
     named 'type' in 'std::result_of<std::packaged_task<void (std::basic_string<char> &)> (std::basic_string<char>)>' 
     typedef typename result_of<_Callable(_Args...)>::type result_type; 
       ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ 
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/thread:135:41: note: in instantiation 
     of template class 'std::_Bind_simple<std::packaged_task<void (std::basic_string<char> &)> 
     (std::basic_string<char>)>' requested here 
     _M_start_thread(_M_make_routine(std::__bind_simple(
             ^
temp.cpp:15:15: note: in instantiation of function template specialization 'std::thread::thread<std::packaged_task<void 
     (std::basic_string<char> &)>, std::basic_string<char> >' requested here 
    std::thread t(std::move(task), std::move(a)); 
      ^
temp.cpp:24:15: note: in instantiation of function template specialization 'spawn_task<void (&)(const 
     std::basic_string<char> &), std::basic_string<char> &>' requested here 
    auto res1 = spawn_task(func_string, str); 
      ^
In file included from temp.cpp:2: 
In file included from /usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/future:38: 
/usr/bin/../lib64/gcc/x86_64-unknown-linux-gnu/4.8.2/../../../../include/c++/4.8.2/functional:1726:50: error: no type 
     named 'type' in 'std::result_of<std::packaged_task<void (std::basic_string<char> &)> (std::basic_string<char>)>' 
     typename result_of<_Callable(_Args...)>::type 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^~~~ 
2 errors generated. 
+1

컴파일 오류를 제공 할 수 있습니까? – Chnossos

+0

@Chnossos가 추가되었습니다. – nnovzver

+0

컴파일은'void func_string (std :: string && x)'와 같은 함수 시그니처의 변경과 함께 작동하고'std :: move (str)'을 사용합니다. 나는 일반적인 경우에 완벽하게 포워딩을 처리하는 방법을 여전히 잘 모르고있다 ... – galop1n

답변

1

, 당신은 모방 할 기능은, 모든 미래의 템플릿 인수를 붕괴 :

다음은 전체 소스 코드 (마이너스 헤더)입니다. here :

template <typename T_> 
using decay_t = typename std::decay<T_>::type; 
template< class T > 
using result_of_t = typename std::result_of<T>::type; 

template <typename F, typename A> 
std::future<result_of_t<decay_t<F>(decay_t<A>)>> spawn_task(F &&f, A &&a) { 
    using result_t = result_of_t<decay_t<F>(decay_t<A>)>; 
    std::packaged_task< result_t(decay_t<A>)> task(std::forward<F>(f)); 
    auto res = task.get_future(); 
    std::thread t(std::move(task), std::forward<A>(a)); 
    t.detach(); 
    return res; 
} 
+0

대단히 감사합니다!) – nnovzver

+0

실제로 한 줄로 변경했는데'std :: packaged_task )> task (std :: move (f));'가 작동했습니다. 'std :: forward'가 없다면 책의 예는 전혀 쓸모가 없다. – nnovzver

+1

@nnovzver'std :: move'는 비 적합합니다. 비 rvalue 요소를 전달하면이 요소에서'move' 할 것이기 때문입니다. 이것은 매우 무례합니다. – Yakk

1

첫째는 호출 가능 목표 함수를 감싼다. 그리고 Callable의 요구 사항 중 하나는 적절한 반환 값을 갖는다는 것입니다. void은 적절한 반환 값이 아닙니다. 나는 시험을 위해 int를 반환하기 위해 기능을 변경 : 당신이 실제 함수 서명과 무엇을 당신이 std::result_of<> 템플릿에서 지정하는 사이에 불일치가있어 같은

int func_string(const std::string &x) 
{ 
    return 1; 
} 

int func_int(int x) 
{ 
    return 2; 
} 

는 둘째가 나에게 보인다.

int func_string(const std::string &x); 
int func_int(int x); 

하지만 당신은 통과됩니다 : 당신의 구체적인 기능 서명은

std::result_of<F(A&&)>::type result_type 

은 해당 변경 :

std::result_of<F(A)>::type result_type 

그리고 모든 컴파일합니다. 당신은 비동기의 documentation 보면

int func_string(const std::string &x) 
{ 
    return 1; 
} 

int func_int(int x) 
{ 
    return 2; 
} 

template <typename F, typename A> 
std::future<typename std::result_of<F(A)>::type> spawn_task(F &&f, A &&a) 
{ 
    typedef typename std::result_of<F(A)>::type result_type; 
    std::packaged_task<result_type(A)> task(std::move(f)); 
    std::future<result_type> res(task.get_future()); 
    std::thread t(std::move(task), std::move(a)); 
    t.detach(); 
    return res; 
} 

int main() 
{ 
    std::string str = "abc"; 

    auto res1 = spawn_task(func_string, str); 
    res1.get(); 
    auto res2 = spawn_task(func_int, 10); 
    res2.get(); 
} 
+1

이 부분은 etheir이 아닙니다. http://coliru.stacked-crooked.com/a/27e5d630470f5e4c – galop1n

+0

@ galop1n 흥미 롭습니다 -이 내용은 VS2013에서 올바르게 컴파일되고 실행됩니다. –

+2

VS 컴파일러를 신뢰하지 마십시오 ... – galop1n

관련 문제