2012-08-08 16 views
17

Jestem zdezorientowany co do funkcjonalności void operator()().Funkcjonalność void operator()()

mógłbyś mi powiedzieć o tym, na przykład:

class background_task 
{ 
public: 

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

background_task f; 

std::thread my_thread(f); 

Oto, dlaczego musimy operator()()? Jakie jest znaczenie pierwszego i drugiego ()? Właściwie znam operację zwykłego operatora, ale ten operator jest zagmatwany.

Odpowiedz

17

Pierwsza () to nazwa operatora - jest to operator, który jest wywoływany, gdy używasz obiektu (). Drugi () dotyczy parametrów, których nie ma.

Oto przykład jak można go używać:

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

fajne, bardziej przejrzyste teraz. –

+0

Czy są jakieś niejawne wywołania operatora()() z wyjątkiem tego jawnego zadania wywołania()? –

+1

@ forester2012, nie musisz zawsze wywoływać go jawnie, chociaż możesz użyć znacznie bardziej niezręcznej składni 'task.operator()()'. Istnieje wiele standardowych algorytmów, które będą wywoływać ten operator wewnętrznie. –

21

Można przeciążać operatora () zadzwonić do obiektu tak, jakby to była funkcja:

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

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

Więc pierwsze nawiasy są zawsze puste: jest to nazwa funkcji: operator(), drugie nawiasy mogą mieć parametry (jak w moim przykładzie), ale nie muszą (jak w twoim przykładzie).

Aby połączyć się z tym operatorem w konkretnym przypadku, należy wykonać czynność podobną do task().

+0

fajne, twoje wyjaśnienie czyni mnie jasnym teraz –

+0

operator()() jest wywoływany tylko bez żadnych parametrów? Czy istnieją inne przypadki, aby go uruchomić? –

+1

@ forester2012, możesz wybrać liczbę parametrów, deklarując parametry w drugim '()' jak pokazano tutaj. Możesz również zadeklarować różne funkcje 'operator()' z różnymi listami parametrów, a C++ wybierze właściwą funkcję na podstawie parametrów używanych podczas jej wywoływania. –

6

Pierwsza część operator() jest sposobem deklarowania funkcji, która jest wywoływana, gdy instancja klasy jest wywoływana jako funkcja. Druga para nawiasów zawierałaby rzeczywiste argumenty.

Z wartości zwracanej i argumentów może to zrobić nieco więcej sensu:

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)); 

W tym kontekście std::thread będzie wewnętrznie powoływania f() wewnątrz wątku, czyli co jest wewnątrz ciała operator() to co robi zrobione wewnątrz tego wątku.

1

Wszystkie wskazówki, które zostały zgłoszone powyżej, są poprawne dla programów sekwencyjnych, tzn. Programów bez wątków. Używanie wątków zmienia się. Po pierwsze, domyślnie parametrami do std :: thread są parametry funkcji i funkcji. Prawdopodobnie były studia Książka "C++ współbieżność w akcji", a autor przedstawia interesujący przykład:

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

Załóżmy tę funkcję:

void do_other_job (int k); W organizmie kodu, należy zrobić:

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

w celu tarło innego wątku.

Tak więc, za pomocą gwintów kompilator interpretuje f (w std :: gwintu my_thread (F);) domyślnie jako funkcję zamiast klasy. Aby zmienić, musisz zainicjować operator(), aby ostrzec kompilatora, który pracuje z klasą. Alternatywą kod może być:

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

Ostatecznie, to nie jest poprawna, za pomocą wątków, karmienie operatora, więc ten kod nie działa:

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

Zdarza się, ponieważ cały kod wewnątrz nawiasy są tylko do odczytu i nie można ich zmienić w czasie wykonywania. Jeśli chcesz wstawić zmienną do konstruktora, musisz ją włączyć do inicjowania wątku. A więc:

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

Będzie działał bez błędów i wykona funkcję do_sth (12) w zarodku wątku.

Mam nadzieję, że pomogłem.