2017-02-10 51 views
6
#include <thread> 
#include <functional> 
#include <utility> 

using namespace std; 

template<typename Callable, typename... Args> 
void Async(Callable&& fn, Args&&... args) 
{ 
    auto fn_wrapper = [](Callable&& fn, Args&&... args) 
    { 
     invoke(forward<Callable>(fn), forward<Args>(args)...); 
    }; 

    // ok 
    fn_wrapper(forward<Callable>(fn), forward<Args>(args)...); 

    // ok 
    async(forward<Callable>(fn), forward<Args>(args)...); 

    // error : no matching function for call to 'async' 
    async(fn_wrapper, forward<Callable>(fn), forward<Args>(args)...); 
} 

void f(int, int) {} 

int main() 
{ 
    Async(f, 1, 2); 
    this_thread::sleep_for(1min); 
} 

Poniższy kod jest ok:Dlaczego "std :: async" nie działa zgodnie z oczekiwaniami?

fn_wrapper(forward<Callable>(fn), forward<Args>(args)...); 

Poniższy kod jest ok:

async(forward<Callable>(fn), forward<Args>(args)...); 

Jednakże poniższy kod jest NIE ok:

// error : no matching function for call to 'async' 
    async(fn_wrapper, forward<Callable>(fn), forward<Args>(args)...); 

Ostatni przypadek nie kompiluje się z fo Błąd llowing:

main.cpp:27:5: fatal error: no matching function for call to 'async' 
    async(fn_wrapper, 
    ^~~~~ 
main.cpp:36:5: note: in instantiation of function template specialization 'Async<void (&)(int, int), int, int>' requested here 
    Async(f, 1, 2); 
    ^

    [...] 

/usr/local/bin/../lib/gcc/x86_64-pc-linux-gnu/6.3.0/../../../../include/c++/6.3.0/future:1739:5: note: candidate template ignored: substitution failure [with _Fn = (lambda at main.cpp:12:9) &, _Args = <void (&)(int, int), int, int>]: no type named 'type' in 'std::result_of<(lambda at main.cpp:12:9) (void (*)(int, int), int, int)>' 
    async(_Fn&& __fn, _Args&&... __args) 

Dlaczego nie ostatni przypadek działa?

+2

A jak ty * * oczekiwać go do pracy? Co dzieje się podczas budowania lub uruchamiania programu? Jakie masz problemy? Do tego momentu * powinieneś * [wiedzieć, jak zadawać dobre pytania] (http://stackoverflow.com/help/how-to-ask). –

+0

Usunięto znacznik [C++ 11], ponieważ 'std :: invoke' nie istniał wtedy. – Quentin

+1

@xmllmx Wyjaśnij słowami, jakie są twoje oczekiwania i dlaczego standard ma się zgadzać z Twoimi oczekiwaniami. Stwórz historię, którą ludzie będą rozumieć, zanim zajrzysz do swojego kodu. –

Odpowiedz

7

Perfect forwarding (&&) działa tylko w kontekście argumentu szablonu. Ale twoja lambda nie jest szablonem. Tak więc (Callable&& fn, Args&&... args) po prostu klepie && na każdym argumencie i w rzeczywistości oznacza "przekazywanie przez referencję rvalue", która nie będzie idealna do przekazania poprawnie.

Ale co ważniejsze, std::async wywołuje funktor jako INVOKE(DECAY(std::forward<F>(f)), DECAY(std::forward<Args>(args))...), więc typy parametrów wyprowadzoną funktora są rzeczywiście zbutwiałeCallable i Args.

Spróbuj opakowanie Zamiast:

auto fn_wrapper = [](auto&& fn, auto&&... args) 
    { 
     invoke(forward<decltype(fn)>(fn), forward<decltype(args)>(args)...); 
    }; 
+0

Czy "auto &&" powinno zapewniać idealne przekazywanie? – xmllmx

+0

Twoje sugerowane opakowane nie kompiluje się: - "Args": pakiet parametrów musi zostać rozszerzony w tym kontekście. - 'std :: forward': nie z 2 przeciążeń można przekonwertować wszystkie typy argumentów " -" std :: invoke ": nie znaleziono pasującej funkcji przeciążonej – JHBonarius

+1

Zaktualizowano. dzięki – rustyx