Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/128.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用std::thread调用重载成员函数_C++_C++11_Visual Studio 2012_Stdthread - Fatal编程技术网

C++ 使用std::thread调用重载成员函数

C++ 使用std::thread调用重载成员函数,c++,c++11,visual-studio-2012,stdthread,C++,C++11,Visual Studio 2012,Stdthread,对于我们需要使用线程跨越的函数,是否可能有重载 我有一个简单的类叫做Complex class Complex { public: Complex():realPart_(0), imagPart_(0){} Complex(double rp, double ip) : realPart_(rp), imagPart_(ip) {} double & real() { return realPart_;} double & imag() {

对于我们需要使用线程跨越的函数,是否可能有重载

我有一个简单的类叫做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();
}

如果没有重载的显示函数采用无符号,则我显示的代码可以正常工作。

这里可以使用lambda,您也可以调用任何对象函数并传入参数:

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

与一些关于这个问题的评论相反,这不是C++11限制ctor参数列表的问题,也不是编译器的问题。线程构造函数可以获取指向成员函数的指针,后跟调用成员函数的对象引用/指针,后跟成员函数参数(如果有)

手头的问题只是一个消除歧义的问题,只要看到
&Complex::display
,编译器就没有机会知道您指的是哪种重载,因为在扣除模板参数时,它不知道构造函数内部的函数指针将与其他参数一起调用,因此只有一元或0元成员函数才有意义

Bluescani和billz展示了两种可能的解决方案:

  • 将lambda传递给线程的构造函数,因为lambda重载解析可以决定调用哪个display函数
  • 将成员函数指针强制转换为正确的函数指针类型,以便编译器知道为模板参数推断选择哪个类型
  • 第三种可能是显式指定函数指针的模板参数,但遗憾的是

    std::thread sqCalc1(&Complex::display,&c1)//不起作用
    

    然而,这对显式的强制转换和参数推导没有太大的影响。无论如何,我更喜欢使用lambda,即使没有这种模糊性,因为您可以在函数调用之前放置断点。

    问题与
    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);
    
    现在,您已经显式请求了
    显示
    重载,该重载返回
    void
    ,并且不带任何参数

    如果编译器支持C++11别名声明,则可以使其更易于阅读:

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

    尽管这不是关于重写成员函数,但感谢@billz提供lambda解决方案的唯一方法是使用“我的”代码,这是线程调用问题的最简单情况,同样,如上所述,使用lambdas解决了这个问题

    #include <thread>
    void f(int a){}
    void f(int a, int b){}
    
    int main()
    {
       std::thread t([=]{ f(2); });
       t.join();
    
       return 0;
    } 
    
    #包括
    void f(int a){}
    void f(inta,intb){}
    int main()
    {
    std::线程t([=]{f(2);});
    t、 join();
    返回0;
    } 
    
    我喜欢。这只是一个演示问题的示例。AFAIK
    std::thread
    构造函数仅支持静态函数指针或适当的函子类作为参数。要调用类成员方法,您需要一个包装类,该类保存实际的类实例以及call.makulik的函数指针,谢谢您的回复。我想知道的是,这是一个C++标准所规定的限制,还是编译器厂商还没有解决这个问题。@ G- MKULIKE,不,<代码> STD::线程< /代码>直接支持调用成员函数。问题在于,
    &Complex::display
    是不明确的,而不是
    std::thread
    的问题,这是一个很好的解决方法。但我想知道为什么不支持重载成员函数。是不可能提供这样的支持,还是他们还没有提供相同的支持?你的确切意思是“重载成员函数”??我在您的代码中看不到任何“重载”。void display(),void display(unsigned nTimes)是复杂类上的两个函数,它们具有相同的名称,但参数不同。@g-makulik他有重载的display,但使用lambda和std::thread没有任何问题。您的第一句话现在错了。如果函数没有重载,语法就非常好,这基本上就是他所要求的。请看这里:当我测试cast时,它编译正常,但执行时崩溃。谢谢!我还发现,在.h中声明的函数的顺序很重要:它应该从参数较少的函数变为参数较多的重载函数。@MickeyTin通常不是这样,顺序并不重要。在这个例子中,这当然无关紧要。我观察到,在我改变顺序之前,我无法编译。编译器一直抱怨参数编号错误,直到我切换函数。我正在构建Android NDK项目。
    using memfunc_type = void (Complex::*)() const;
    memfunc_type memfunc = &Complex::display;
    std::thread sqCalc1(memfunc, &c1);
    std::thread sqCalc2(memfunc, &c2);
    
    #include <thread>
    void f(int a){}
    void f(int a, int b){}
    
    int main()
    {
       std::thread t([=]{ f(2); });
       t.join();
    
       return 0;
    }