2013-04-22 8 views
8

Si consideri il codice qui sotto:std :: decadimento asincrono (perdente) riferimento di rvalue nell'aggiornamento di Visual Studio 2012 2. Eventuali soluzioni alternative?

#include <memory> 
#include <future> 

using namespace std; 

template <typename T, typename Work> 
void Test2(future<T> f, Work w) 
{ 
    async([](future<T> && f, Work w) 
         {}, move(f), move(w)); 
} 

int main() 
{ 
    future<int> x = std::async([]()->int{ 
     std::this_thread::sleep_for(std::chrono::microseconds(200)); 
     return 10; 
    }); 

    Test2(std::move(x), [](int x){}); 
    return 0; 
} 

Quanto sopra, non riesce con il seguente errore del compilatore:

Error 1 error C2664: 'void Test2::::operator ()(std::future<_Ty> &&,Work) const' : cannot convert parameter 1 from 'std::future<_Ty>' to 'std::future<_Ty> &&' c:\program files (x86)\microsoft visual studio 11.0\vc\include\xrefwrap 98 1 ConsoleApplication6

GCC 4.7.2 compila bene http://ideone.com/KhMiV6

Prima di andare avanti e di rapporto su Microsoft Connect:

1) Si tratta di un errore nella parte di VC11 o è in realtà d comportamento?

2) Qualcuno sa di una soluzione alternativa per questo?

MODIFICA: l'ho segnalato su Microsoft Connect here. Per una risoluzione più rapida, sei incoraggiato a svenderlo.

risposta

5

Hm, sembra un bug in VC11. Apparentemente l'implementazione di async non inoltra realmente gli argomenti ma li copia.

Dalla cima della mia testa vorrei creare un piccolo wrapper per il rvalue che si muovono-costruisce l'elemento quando l'involucro viene copiato:

template <typename T> 
    struct rvref_wrapper { 
     rvref_wrapper(T&& value) : value_(std::move(value)) {} 
     rvref_wrapper(rvref_wrapper const& other) : value_ (other.get()) {} 
     T&& get() const { return std::move(value_); } 
     mutable T value_; 
    }; 

    template <typename T> 
    auto rvref(T&& x) -> rvref_wrapper<typename decay<T>::type> { 
     return std::move(x); 
    } 

Allora dovreste modificare il vostro scenario di test, in modo da che la lambda nel Test2 prende l'involucro al posto del future stesso:

template <typename T, typename Work> 
    void Test2(future<T> f, Work w) 
    { 
     async([](rvref_wrapper<future<T>> fr, Work w) { 
      // acquire future<T>&& here 
      future<T> f(fr.get()); 
      // e.g. call work with future value 
      w(f.get()); 
     }, rvref(f), move(w)); 
    } 

    int main() 
    { 
     future<int> x = std::async([]()->int{ 
      std::this_thread::sleep_for(std::chrono::microseconds(200)); 
      return 10; 
     }); 

     Test2(std::move(x), [](int x){}); 
     return 0; 
    } 

sembra un po 'brutto, ma almeno si compila. Spero che ti aiuti!

+0

Ispirato da std :: ref, stavo pensando esattamente alla stessa soluzione. Un problema da notare con il tuo codice è che il parametro 'f' di Test2 andrà fuori campo e verrà distrutto dal momento in cui raggiunge la riga' future && f = fr.get(); '. Ho risolto questo nel mio codice (abbastanza divertente ho avuto lo stesso identico problema). Sono interessato a vedere come lo sistemerai. Grazie per aver risposto. –

+0

Oh, giusto, ma puoi anche memorizzare un 'T mutabile '(invece di' T && ') nella tua classe wrapper e passare questo sulla copia. Quindi il wrapper ha persino la proprietà del tuo futuro. –

+0

Questa era esattamente la mia soluzione. Si prega di modificare la risposta per riflettere la soluzione corretta, in modo che io possa accettare :) –

Problemi correlati