2012-08-08 18 views
17

Sono confuso circa la funzionalità di void operator()().Funzionalità di void operator()()

Potrebbe dirmi di questo, per esempio:

class background_task 
{ 
public: 

    void operator()() const 
    { 
     do_something(); 
     do_something_else(); 
    } 
}; 

background_task f; 

std::thread my_thread(f); 

Qui, perché abbiamo bisogno di operator()()? Qual è il significato del primo e del secondo ()? In realtà, conosco il funzionamento dell'operatore normale, ma questo operatore è fonte di confusione.

risposta

17

Il primo () è il nome dell'operatore - è l'operatore che viene richiamato quando si utilizza () sull'oggetto. Il secondo () è per i parametri, di cui non ce ne sono.

Ecco un esempio di come si dovrebbe utilizzare:

background_task task; 
task(); // calls background_task::operator() 
+0

fresco, più chiaro ora. –

+0

Esistono chiamate implicite per operator()() ad eccezione di questa esplicita chiamata call()? –

+1

@ forester2012, no devi sempre chiamarlo in modo esplicito anche se puoi usare anche la sintassi 'task.operator()()' molto più scomoda. Esistono molti algoritmi standard che chiameranno questo operatore internamente. –

21

Si può sovraccaricare l'operatore () di chiamare l'oggetto come se fosse una funzione:

class A { 
public: 
    void operator()(int x, int y) { 
     // Do something 
    } 
}; 

A x; 
x(5, 3); // at this point operator() gets called 

Quindi la prima parentesi sono sempre vuoto: questo è il nome della funzione: operator(), le seconde parentesi potrebbero avere parametri (come nel mio esempio), ma non devono (come nel tuo esempio).

Quindi per chiamare questo operatore nel caso specifico si farebbe qualcosa come task().

+0

cool, la tua spiegazione mi rende chiaro ora –

+0

operator()() viene chiamato solo senza parametri? C'è qualche altro caso per eseguirlo? –

+1

@ forester2012, puoi scegliere quanti parametri ci sono dichiarando i parametri all'interno del secondo '()' come mostrato qui. Puoi anche dichiarare diverse funzioni 'operator()' con diversi elenchi di parametri e C++ sceglierà quello corretto in base ai parametri che usi quando lo chiami. –

6

La prima parte operator() è il modo per dichiarare la funzione che viene chiamata quando un'istanza della classe viene invocata come una funzione. La seconda coppia di parentesi contiene gli argomenti effettivi.

Con un valore di ritorno e argomenti ciò potrebbe rendere un po 'più senso:

class Adder{ 
public: 
int operator()(int a, int b){ 
    //operator() -- this is the "name" of the operator 
    //   in this case, it takes two integer arguments. 
    return a+b; 
} 
}; 
Adder a; 
assert(5==a(2,3)); 

In questo contesto, il std::thread sarà internamente invocare f() all'interno del filo, ossia tutto ciò che è all'interno del corpo di operator() è quello che ottiene fatto all'interno di quel thread.

1

Tutti i suggerimenti forniti in precedenza sono corretti per programmi sequenziali, ovvero programmi senza thread. Usando le discussioni le cose cambiano. Prima di tutto, i parametri predefiniti per std :: thread sono parametri di funzioni e funzioni. Probabilmente si stava studiando il libro "concorrenza C++ in azione", e l'autore mostra un esempio interessante:

void do_some_work(); 
thread my_thread(do_some_work); //thread receives the function address 

Supponiamo questa funzione:

vuoto do_other_job (int k); Nel corpo del codice, si dovrebbe fare:

k=3; 
thread my_thread2(do_other_job, k); 

al fine di generare un altro thread.

Quindi, utilizzando i thread il compilatore interpreta f (in std :: thread my_thread (f);) come funzione predefinita anziché come classe. Per cambiare devi avviare un operatore() per avvisare il compilatore che stai lavorando con una classe. Un codice alternativo potrebbe essere:

class background_task{ 
public: 
background_task(){ 
do_sth(); 
do_sth_else(); 
} 
void operator()(){} 
}; 
background_task f; 
thread mythread10(f); 

Infine, non è corretto, utilizzando thread, alimentando l'operatore, pertanto questo codice non funziona:

void operator()(int x){ 
do_sth(); 
cout<<"x = "<<x<<endl; 
} 

Succede perché tutto il codice all'interno le parentesi sono di sola lettura e non possono essere modificate durante il tempo di esecuzione. Se si mira a inserire una variabile nel costruttore, è necessario inserirlo nell'inizializzazione del thread. Quindi:

class backg{ 
public: 
backg(int i){ 
    do_sth(i); 
    } 
void operator()(){} 
}; 
int main(){ 
thread mythread{ backg(12) }; //using c++11 
return 0; 
} 

verrà eseguito senza errori, e si esibirà la funzione do_sth (12) nel thread generato.

Spero di aver aiutato.