Вызов перегруженных функций-членов с использованием std :: thread

Возможно ли иметь перегрузки для функций, которые мы должны охватить, используя потоки?

У меня есть простой класс под названием Complex.

class Complex
{
public:
Complex():realPart_(0), imagPart_(0){}

Complex(double rp, double ip) : realPart_(rp), imagPart_(ip) {}

double & real() { return realPart_;}
double & imag() { return imagPart_;}

const double & real() const { return realPart_;}
const double & imag() const { return imagPart_;}

double square() const {return realPart_*realPart_ - imagPart_*imagPart_;}

void display() const
{
std::cout << "Square of the Complex number (" << realPart_ << ") + i (" << imagPart_ << " ) is " << square() << std::endl;
}

void display(unsigned nTimes) const {while(nTimes-- > 0)display();}

private:

double realPart_;
double imagPart_;

};

void Test3()
{
Complex c1(1, 0.74), c2(2, 0.35);

std::thread sqCalc1(&Complex::display, &c1);
std::thread sqCalc2(&Complex::display, &c2);

sqCalc1.join();
sqCalc2.join();
}

Я получаю ошибки, когда я строю этот код.

error C2661: 'std::thread::thread' : no overloaded function takes 2 arguments

Если нет перегруженной функции отображения, которая принимает неподписанный код, показанный мною код работает нормально.

10

Решение

Проблема не в чем std::thread (ошибка вводит в заблуждение), что можно показать, переставив код:

auto memfunc = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);

Ошибка будет в первой строке, потому что, как сказали другие ответы, выражение &Complex::display ссылается на перегруженную функцию, и компилятор не знает, какую именно вы имеете в виду.

Вы можете выбрать желаемую перегрузку, сообщив компилятору тип функции, которую вы пытаетесь вызвать, с приведением типа или так:

void (Complex::*memfunc)() const = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);

Теперь вы явно запросили display перегрузка, которая возвращает void и не принимает никаких аргументов.

Если ваш компилятор поддерживает объявления псевдонимов C ++ 11, вы можете сделать это проще для чтения:

using memfunc_type = void (Complex::*)() const;
memfunc_type memfunc = &Complex::display;
std::thread sqCalc1(memfunc, &c1);
std::thread sqCalc2(memfunc, &c2);
10

Другие решения

Вопреки некоторым комментариям по этому вопросу, это не проблема C ++ 11, ограничивающая список аргументов ctor, и не проблема компилятора. Конструктор std :: thread может принимать указатель на функцию-член, за которой следует ссылка на объект / указатель, при котором должна быть вызвана функция-член, а затем аргументы функции-члена (если они есть).

Проблема под рукой — просто проблема устранения неоднозначности, просто видя &Complex::displayу компилятора нет шансов узнать, какую из перегрузок вы имеете в виду, потому что при вычитании аргументов шаблона он не знает, что внутри конструктора будет вызываться указатель функции с другими аргументами и что, следовательно, только унарный или 0-членный член функция имеет смысл.

2 Возможные решения были показаны bluescarni и billz:

  1. Передайте лямбду в конструктор потока, потому что внутри лямбда-разрешения перегрузки можно определить, какая функция отображения вызывается.
  2. Приведите указатель на функцию-член к правильному типу указателя на функцию, чтобы компилятор знал, какой из них выбрать для вывода аргумента шаблона.

Третья возможность состоит в том, чтобы явно указать параметр шаблона указателя функции, но, к сожалению, невозможно явно создать экземпляр шаблонных конструкторов:

std::thread sqCalc1<Complex::*()const>(&Complex::display, &c1); //doesn't work

Однако это не будет иметь большого значения для явного приведения и вывода аргумента. и я предпочитаю использовать лямбды в любом случае, во всех случаях, даже если такой двусмысленности нет, просто потому, что вы можете поставить точку останова прямо перед вызовом функции.

5

Здесь можно использовать лямбду, вы можете вызвать любую функцию объекта и передать аргументы:

int main()
{
Complex c1(1, 0.74), c2(2, 0.35);

std::thread sqCalc1([=]{c1.display();});
std::thread sqCalc2([=]{c2.display(3);});

sqCalc1.join();
sqCalc2.join();
return 0;
}
4

Может быть, поможет определение типов и кастинг?

typedef void (Complex::*display_0)() const;
typedef void (Complex::*display_1)(unsigned) const;

std::thread sqCalc1(display_0(&Complex::display), &c1);
std::thread sqCalc2(display_0(&Complex::display), &c2);
4

Хотя это не о переопределении член Функция, единственный способ поблагодарить @billz за лямбда-решение — внести свой вклад с помощью «моего» кода, что является простейшим случаем проблемы вызова потока, опять же, решаемой с помощью лямбда-выражений, как предложено выше.

#include <thread>
void f(int a){}
void f(int a, int b){}

int main()
{
std::thread t([=]{ f(2); });
t.join();

return 0;
}
0
По вопросам рекламы [email protected]