155

New Signal Slot Syntaxで説明されているように、Qt 5 の新しいシグナル/スロット構文 (メンバー関数へのポインターを使用) を理解するのに苦労しています。これを変更してみました:

QObject::connect(spinBox, SIGNAL(valueChanged(int)),
                 slider, SLOT(setValue(int));

これに:

QObject::connect(spinBox, &QSpinBox::valueChanged,
                 slider, &QSlider::setValue);

しかし、コンパイルしようとするとエラーが発生します。

エラー: 呼び出しに一致する関数がありませんQObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

Linuxでclangとgccを試しましたが、どちらも-std=c++11.

私は何を間違っていますか、どうすれば修正できますか?

4

4 に答える 4

283

ここでの問題は、その名前の 2 つの信号があることです:QSpinBox::valueChanged(int)QSpinBox::valueChanged(QString). Qt 5.7 から、必要なオーバーロードを選択するためのヘルパー関数が提供されているため、次のように記述できます。

connect(spinbox, qOverload<int>(&QSpinBox::valueChanged),
        slider, &QSlider::setValue);

Qt 5.6 以前では、正しいタイプにキャストして、どちらを選択するかを Qt に伝える必要があります。

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
        slider, &QSlider::setValue);

私は知っています、それは醜いです。しかし、これを回避する方法はありません。今日のレッスンは:シグナルとスロットを過負荷にしないでください!


補遺: キャストについて本当に厄介なのは、

  1. 1 つはクラス名を 2 回繰り返します
  2. void通常(シグナルの場合)であっても、戻り値を指定する必要があります。

そのため、この C++11 スニペットを使用することがあります。

template<typename... Args> struct SELECT { 
    template<typename C, typename R> 
    static constexpr auto OVERLOAD_OF( R (C::*pmf)(Args...) ) -> decltype(pmf) { 
        return pmf;
    } 
};

使用法:

connect(spinbox, SELECT<int>::OVERLOAD_OF(&QSpinBox::valueChanged), ...)

個人的にはあまり役に立たないと思います。Creator (または IDE) が PMF の取得操作をオートコンプリートするときに正しいキャストを自動的に挿入すると、この問題は自然に解消されると思います。しかし、その間...

注: PMF ベースの接続構文には C++11 は必要ありません


補遺 2 : Qt 5.7 では、上記の回避策をモデルにして、これを軽減するためにヘルパー関数が追加されました。主なヘルパーはqOverload( と も持っていますqConstOverload)qNonConstOverloadです。

使用例(ドキュメントから):

struct Foo {
    void overloadedFunction();
    void overloadedFunction(int, QString);
};

// requires C++14
qOverload<>(&Foo:overloadedFunction)
qOverload<int, QString>(&Foo:overloadedFunction)

// same, with C++11
QOverload<>::of(&Foo:overloadedFunction)
QOverload<int, QString>::of(&Foo:overloadedFunction)

補遺 3 : オーバーロードされた信号のドキュメントを見ると、オーバーロードの問題の解決策がドキュメント自体に明確に記載されています。たとえば、https://doc.qt.io/qt-5/qspinbox.html#valueChanged-1は言う

注: シグナル valueChanged は、このクラスでオーバーロードされます。関数ポインター構文を使用してこのシグナルに接続するために、Qt は次の例に示すように、関数ポインターを取得するための便利なヘルパーを提供します。

   connect(spinBox, QOverload<const QString &>::of(&QSpinBox::valueChanged),
[=](const QString &text){ /* ... */ });
于 2013-05-28T15:18:14.503 に答える
16

エラーメッセージは次のとおりです。

エラー: 呼び出しに一致する関数がありませんQObject::connect(QSpinBox*&, <unresolved overloaded function type>, QSlider*&, void (QAbstractSlider::*)(int))

これの重要な部分は、「未解決のオーバーロードされた関数型」についての言及です。コンパイラは、あなたが意味するのQSpinBox::valueChanged(int)か、それともQSpinBox::valueChanged(QString).

過負荷を解決するには、いくつかの方法があります。

  • に適切なテンプレート パラメータを提供します。connect()

    QObject::connect<void(QSpinBox::*)(int)>(spinBox, &QSpinBox::valueChanged,
                                             slider,  &QSlider::setValue);
    

    これにより、.を受け取るオーバーロードに強制的connect()に解決されます。&QSpinBox::valueChangedint

    スロット引数に未解決のオーバーロードがある場合は、2 番目のテンプレート引数を に指定する必要がありますconnect()。残念ながら、最初に推論されるように要求する構文はないため、両方を指定する必要があります。そんなときは、2 番目のアプローチが役に立ちます。

  • 正しいタイプの一時変数を使用してください

    void(QSpinBox::*signal)(int) = &QSpinBox::valueChanged;
    QObject::connect(spinBox, signal,
                     slider,  &QSlider::setValue);
    

    への割り当てによりsignal、目的のオーバーロードが選択され、テンプレートに正常に代入できるようになりました。これは 'slot' 引数でも同じように機能し、その場合はそれほど面倒ではありません。

  • 変換を使用する

    static_castこれは、言語の保護を解除するのではなく、単なる強制であるため、ここでは避けることができます。私は次のようなものを使用します:

    // Also useful for making the second and
    // third arguments of ?: operator agree.
    template<typename T, typename U> T&& coerce(U&& u) { return u; }
    

    これにより、次のように書くことができます

    QObject::connect(spinBox, coerce<void(QSpinBox::*)(int)>(&QSpinBox::valueChanged),
                     slider, &QSlider::setValue);
    
于 2016-05-18T14:42:44.783 に答える
8

実際、スロットをラムダでラップするだけで、次のようになります。

connect(spinbox, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged),
    slider, &QSlider::setValue);

見栄えが良くなります。:\

于 2014-06-07T11:08:45.477 に答える