Функциональность оператора void()()
Я запутался в функциональности void operator()()
.
Не могли бы вы рассказать мне об этом, например:
class background_task
{
public:
void operator()() const
{
do_something();
do_something_else();
}
};
background_task f;
std::thread my_thread(f);
Здесь нам нужно operator()()
? В чем смысл первого и второго ()
? На самом деле, я знаю операцию нормального оператора, но этот оператор запутан.
Ответы
Ответ 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) в порожденном потоке.
Надеюсь, я помог.