Подтвердить что ты не робот

Функциональность оператора void()()

Я запутался в функциональности void operator()().

Не могли бы вы рассказать мне об этом, например:

class background_task
{
public:

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

background_task f;

std::thread my_thread(f);

Здесь нам нужно operator()()? В чем смысл первого и второго ()? На самом деле, я знаю операцию нормального оператора, но этот оператор запутан.

4b9b3361

Ответ 1

Первый () - это имя оператора - это оператор, который вызывается при использовании () объекта. Второй () для параметров, которых нет.

Вот пример того, как вы его используете:

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

Ответ 2

Вы можете перегрузить оператор () для вызова вашего объекта, как если бы это была функция:

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

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

Итак, первые круглые скобки всегда пусты: это имя функции: operator(), во вторых круглых скобках могут быть параметры (как в моем примере), но они не обязательно (как в вашем примере).

Итак, чтобы вызвать этот оператор в вашем конкретном случае, вы бы сделали что-то вроде task().

Ответ 3

Первая часть operator() - это способ объявить функцию, которая вызывается, когда экземпляр класса вызывается как функция. Вторая пара скобок будет содержать фактические аргументы.

С возвращаемым значением и аргументами это может иметь несколько большее значение:

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

В этом контексте std::thread будет внутренне вызывать f() внутри потока, то есть все, что находится внутри тела operator(), это то, что делается внутри этого потока.

Ответ 4

Все намеки, которые были внесены выше, верны для последовательных программ, я имею в виду программы без потоков. Использование нитей меняется. Прежде всего, по умолчанию параметры std:: thread являются параметрами функций и функций. Вероятно, вы изучали книгу "С++ concurrency в действии", и автор показывает интересный пример:

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

Предположим, что эта функция:

void do_other_job (int k); В теле кода вы должны сделать:

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

чтобы создать другой поток.

Итак, используя потоки, компилятор интерпретирует f (в ​​ std:: thread my_thread (f);) по умолчанию как функцию вместо класса. Чтобы изменить это, вы должны инициировать оператор(), чтобы предупредить компилятор, с которым вы работаете с классом. Альтернативный код может быть:

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

В конце концов, это не правильно, используя потоки, подавая оператора, поэтому этот код не работает:

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

Это происходит потому, что весь код внутри скобок доступен только для чтения и не может быть изменен во время выполнения. Если вы хотите вставить переменную в конструктор, она должна быть помещена в инициализацию потока. Итак:

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

Будет работать без ошибок и будет выполнять функцию do_sth (12) в порожденном потоке.

Надеюсь, я помог.