2016-03-31 9 views
8
#include<iostream> 
#include<thread> 
using namespace std; 

void f1(double& ret) { 
    ret=5.; 
} 

int main() { 
    double ret=0.; 
    thread t1(f1, ret); 
    t1.join(); 
    cout << "ret=" << ret << endl; 
} 

Il codice di cui sopra non riesce compilation con il seguente error message:C++ Discussione prendendo argomento di riferimento non è riuscito compilare

g++ -std=c++14 -O2 -Wall -pedantic -pthread main.cpp && ./a.out 
In file included from /usr/local/include/c++/5.3.0/thread:39:0, 
       from main.cpp:2: 
/usr/local/include/c++/5.3.0/functional: In instantiation of 'struct std::_Bind_simple<void (*(double))(double&)>': 
/usr/local/include/c++/5.3.0/thread:137:59: required from 'std::thread::thread(_Callable&&, _Args&& ...) [with _Callable = void (&)(double&); _Args = {double&}]' 
main.cpp:11:21: required from here 
/usr/local/include/c++/5.3.0/functional:1505:61: error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>' 
     typedef typename result_of<_Callable(_Args...)>::type result_type; 
                  ^
/usr/local/include/c++/5.3.0/functional:1526:9: error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>' 
     _M_invoke(_Index_tuple<_Indices...>) 
     ^

ho capito che posso usare std::ref() per passare l'argomento. Ma se passo il valore, perché è un errore dal momento che thread deve semplicemente copiare l'argomento per il valore e passare alcuni oggetti memorizzati all'interno del thread per associare l'argomento di riferimento della funzione f1.

Sento che se riesco a capire cosa sta facendo questo result_of e perché sta dando un errore, posso capire meglio il motivo. Quindi qualcuno potrebbe guidarmi attraverso l'errore msg? Soprattutto il significato di std::_Bind_simple<void (*(double))(double&)> e std::result_of<void (*(double))(double&)>.

EDIT: So che se si passa un valore, il thread funzionerà solo sulla copia e non ha alcun effetto dopo il ritorno del thread. Questa non è la mia preoccupazione. Voglio sapere il motivo per cui sta dando l'errore ora, ma non stavo dando errore altri post su SO come la seguente: Difference between pointer and reference as thread parameter

+0

@Barry, hai perso "la porzione evidenziata" con la tua modifica. –

+0

@JonathanWakely risolto. – Barry

risposta

12

lo so se mi passa un valore, il filo funziona solo sulla copia e non ha alcun effetto dopo il ritorno del thread.

No, non è corretto. Il codice non dovrebbe fare una copia in silenzio e lavorare sulla copia, lo standard dice che non deve nemmeno compilare.

Lo standard richiede che gli argomenti della funzione chiamata vengano copiati (nella memoria gestita dal runtime C++) e quindi le copie vengano inoltrate come valori rvalori. Quindi nell'esempio f1 viene passato un valore di tipo double e il parametro di tipo double& non può essere associato a tale valore.

La ragione del principio richiede che è così non c'è copia silenziosa e la perdita dei dati: se la funzione richiede un riferimento modificabile allora non verrà compilato a meno che non si passa un riferimento in modo esplicito utilizzando un reference_wrapper.

L'errore del compilatore che si verifica coinvolge result_of perché è così che ho fatto GCC's std::thread verificare se la funzione può essere chiamata con gli argomenti forniti. Uso result_of<decltype(&f1)(double)> per verificare se il puntatore funzione &f1 (che è di tipo void(*)(double&)) può essere chiamato un rvalue di tipo double. Esso non può essere chiamato con un argomento di questo tipo, in modo che il tipo annidato result_of<decltype(&f1)(double)>::type non è definito, in modo che il compilatore dice:

error: no type named 'type' in 'class std::result_of<void (*(double))(double&)>' 

L'errore è un po 'di confusione perché le regole dichiaratore C++ significa che decltype(&f1)(double) ottiene visualizzato come void(*(double))(double&).

Questa non è la mia preoccupazione. Voglio sapere perché sta dando errore ora, ma non stava dando errore ad altri post su SO

Questi post utilizzavano un vecchio compilatore pre-C++ 11 o non conforme che non soddisfaceva i requisiti dello standard C++ 11 e compilato in modo errato il codice.

+0

da http://en.cppreference.com/w/cpp/thread/thread/thread, dice chiaramente che copierà/trasferirà gli argomenti in ** storage accessibile ai thread ** – Rich

+1

Quindi? Ciò non significa che dovrebbe essere compilato. Assicurati di aver aggiornato la mia risposta per vedere l'ultima versione che spiega che le copie vengono inoltrate come valori rvalue, quindi non possono associare parametri di riferimento non costanti. –

+0

Puoi elaborare l'errore 'std :: result_of'? È quello che sta cercando di fare ciò che lo standard richiede, come hai detto, cioè passare le copie come valori? – Rich

1

La risposta di Jonathan è definitiva. Il tempo trascorso a studiarlo sarebbe stato un tempo ben speso.

Nel frattempo, la modifica del codice quindi farà quello che vuoi - e cioè inviare un riferimento di nella funzione di filo:

thread t1(f1, std::ref(ret)); 
Problemi correlati