Возможно ли иметь перегрузки для функций, которые мы должны охватить, используя потоки?
У меня есть простой класс под названием 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
Если нет перегруженной функции отображения, которая принимает неподписанный код, показанный мною код работает нормально.
Проблема не в чем 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);
Вопреки некоторым комментариям по этому вопросу, это не проблема C ++ 11, ограничивающая список аргументов ctor, и не проблема компилятора. Конструктор std :: thread может принимать указатель на функцию-член, за которой следует ссылка на объект / указатель, при котором должна быть вызвана функция-член, а затем аргументы функции-члена (если они есть).
Проблема под рукой — просто проблема устранения неоднозначности, просто видя &Complex::display
у компилятора нет шансов узнать, какую из перегрузок вы имеете в виду, потому что при вычитании аргументов шаблона он не знает, что внутри конструктора будет вызываться указатель функции с другими аргументами и что, следовательно, только унарный или 0-членный член функция имеет смысл.
2 Возможные решения были показаны bluescarni и billz:
Третья возможность состоит в том, чтобы явно указать параметр шаблона указателя функции, но, к сожалению, невозможно явно создать экземпляр шаблонных конструкторов:
std::thread sqCalc1<Complex::*()const>(&Complex::display, &c1); //doesn't work
Однако это не будет иметь большого значения для явного приведения и вывода аргумента. и я предпочитаю использовать лямбды в любом случае, во всех случаях, даже если такой двусмысленности нет, просто потому, что вы можете поставить точку останова прямо перед вызовом функции.
Здесь можно использовать лямбду, вы можете вызвать любую функцию объекта и передать аргументы:
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;
}
Может быть, поможет определение типов и кастинг?
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);
Хотя это не о переопределении член Функция, единственный способ поблагодарить @billz за лямбда-решение — внести свой вклад с помощью «моего» кода, что является простейшим случаем проблемы вызова потока, опять же, решаемой с помощью лямбда-выражений, как предложено выше.
#include <thread>
void f(int a){}
void f(int a, int b){}
int main()
{
std::thread t([=]{ f(2); });
t.join();
return 0;
}