web-dev-qa-db-ja.com

QT:テンプレート化されたQ_OBJECTクラス

QObjectを継承するテンプレートクラスを持つことは可能ですか(その宣言にQ_OBJECTマクロがあります)?

スロット用のアダプターのようなものを作成したいのですが、スロットは任意の数の引数を取ることができます(引数の数はテンプレート引数に依存します)。

試してみたところ、リンカエラーが発生しました。このテンプレートクラスでgmakeまたはmocが呼び出されていないようです。これを行う方法はありますか?多分明示的にテンプレートをインスタンス化することによって?

43
BЈовић

テンプレートとQ_OBJECTを混在させることはできませんが、タイプのサブセットがある場合は、次のようにスロットと信号をリストできます。

    class SignalsSlots : public QObject
    {
        Q_OBJECT

    public:
        explicit SignalsSlots(QObject *parent = 0) :
            QObject(parent) {}

    public slots:
        virtual void writeAsync(int value) {}
        virtual void writeAsync(float value) {}
        virtual void writeAsync(double value) {}
        virtual void writeAsync(bool state) {}
        virtual void writeAsync(svga::SSlideSwitch::SwitchState state) {}   

    signals:
        void readAsynkPolledChanged(int value);
        void readAsynkPolledChanged(float value);
        void readAsynkPolledChanged(double value);
        void readAsynkPolledChanged(bool state);
        void readAsynkPolledChanged(svga::SSlideSwitch::SwitchState state);
    };
...
template <class T>
class Abstraction : public SignalsSlots
{...
35
Jonas W

いくつかの制限を考慮に入れます:できます。最初に慣れてください(まだ慣れていない場合) https://doc.qt.io/archives/qq/qq16-dynamicqobject.html 。 -それはそれを実装するのに役立ちます。制限について:テンプレートQObjectクラス、つまりQObjectから派生したテンプレートクラスを持つことができますが、

  1. Mocにコンパイルするように指示しないでください。
  2. Q_OBJECTは単なるマクロであり、実際のコンテンツである仮想インターフェースと他のものに置き換える必要があります:)
  3. QMetaObjectアクティベーション(上記の仮想インターフェイスと、Q_OBJECTから取得されるオブジェクト情報データにも注意してください)と他のいくつかの機能を実装すると、テンプレートQObject(テンプレートスロットがある場合でも)を使用できます
  4. しかし、私はなんとか引き金を引くことができました-このクラスを別のクラスのベースとして単純に使用することはできません。
  5. 他にもいくつか欠点がありますが、詳細な調査で明らかになると思います。

これがお役に立てば幸いです。

12
milyaaf

テンプレートとQ_OBJECTを混在させることはまだ不可能ですが、ユースケースによっては、新しい「接続」構文を使用できます。これにより、少なくともテンプレートスロットを使用できます。

古典的な非機能的なアプローチ:

class MySignalClass : public QObject {
  Q_OBJECT
public:

signals:
  void signal_valueChanged(int newValue);
};     


template<class T>
class MySlotClass : public QObject {
  Q_OBJECT
public slots:
  void slot_setValue(const T& newValue){ /* Do sth. */}
};

望ましい使用法ですがコンパイルできません:

MySignalClass a;
MySlotClass<int> b;

QObject::connect(&a, SIGNAL(signal_valueChanged(int)),
                 &b, SLOT(slot_setValue(int)));

エラー:テンプレートクラスはQ_OBJECT(MySlotClassの場合)でサポートされていません。

新しい 'connect'-syntaxを使用するソリューション:

// Nothing changed here
class MySignalClass : public QObject {
  Q_OBJECT
public:

signals:
  void signal_valueChanged(int newValue);
};


// Removed Q_OBJECT and slots-keyword
template<class T>
class MySlotClass : public QObject {  // Inheritance is still required
public:
  void slot_setValue(const T& newValue){ /* Do sth. */}
};

これで、目的の「MySlotClass」オブジェクトをインスタンス化して、適切なシグナルエミッターに接続できます。

  MySignalClass a;
  MySlotClass<int> b;

  connect(&a, &MySignalClass::signal_valueChanged,
          &b, &MySlotClass<int>::slot_setValue);

結論:テンプレートスロットを使用することは可能です。 Q_OBJECTがないためにコンパイラエラーが発生するため、テンプレート信号の送信は機能しません。

3
Anonymous

テンプレートを明示的にインスタンス化してみたところ、次のようになりました。

core_qta_qt_publisheradapter.hpp:96:エラー:Q_OBJECTでサポートされていないテンプレートクラス

それが私の質問の答えだと思います。

[〜#〜]編集[〜#〜]

実際、テンプレートクラス定義全体をヘッダーに配置すると、qtプリプロセッサで処理されず、リンカーエラーが発生します。したがって、足りないメソッドを追加した場合、それが可能になるはずです。

EDIT#2

このライブラリ は、まさに私が望んでいたことを実行しました-スロットに署名が定義されていないカスタム信号/スロットメカニズムを使用するため。

1
BЈовић