16

スレッドを使用してスパンする必要がある関数のオーバーロードを持つことは可能ですか?

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

符号なしを取るオーバーロードされた表示関数がない場合、私が示したコードは正常に動作します。

4

5 に答える 5

22

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);
于 2013-01-13T18:56:37.493 に答える
6

質問に対するいくつかのコメントに反して、これは C++ 11 が ctor 引数リストを制限する問題ではなく、コンパイラの問題でもありません。std::thread コンストラクターは、メンバー関数へのポインターを取り、その後にメンバー関数が呼び出されるオブジェクト参照/ポインターが続き、その後にメンバー関数の引数 (存在する場合) が続きます。

目の前の問題は単なる曖昧さ回避の問題です. を見るだけ&Complex::displayでは、コンパイラはあなたが意味するオーバーロードのどれかを知る機会がありません.したがって、単項または 0 項メンバ関数のみが意味を持ちます。

2 bluescarni と billz によって可能な解決策が示されています。

  1. スレッドのコンストラクターにラムダを渡します。これは、ラムダのオーバーロード解決の内部で、どの表示関数が呼び出されるかを決定できるためです。
  2. メンバー関数ポインターを正しい関数ポインター型にキャストして、コンパイラーがテンプレート引数推定のためにどれを選択するかを認識できるようにします。

3 つ目の方法は、関数ポインターのテンプレート パラメーターを明示的に指定することですが、残念ながら、テンプレート化されたコンストラクターを明示的にインスタンス化することはできません。

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

ただし、これは明示的なキャストと引数の推論に大きな違いはありません。関数呼び出しの直前にブレークポイントを配置できるという理由だけで、そのようなあいまいさがなくても、とにかくラムダを使用することを好みます。

于 2013-01-11T13:59:02.077 に答える
6

ここでラムダを使用できます。任意のオブジェクト関数を呼び出して、引数を渡すこともできます。

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;
}
于 2013-01-11T10:49:26.750 に答える
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);
于 2013-01-11T13:14:32.293 に答える
0

メンバー関数をオーバーライドすることではありませんが、@billz にラムダ ソリューションを提供してくれたことに感謝する唯一の方法は、「my」コードを提供することです。これは、スレッド呼び出しの問題の最も単純なケースであり、上記で提案したようにラムダで解決されます。

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

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

   return 0;
} 
于 2015-04-23T08:20:29.303 に答える