16

最初に、以下はQt 5.0.0ベータ1までは正常に機能しましたが(おそらくベータ2とRCも、わかりません)、Qt5.0.0の最終リリースバージョンでは失敗します。Qt5.0.0の最終リリースバージョンで見られた結果のみを参照したいと思います。したがって、おそらくこれはQt5の最近の変更と関係があります。

C ++側では、名前空間に一連のクラス(QObjectから派生)があります(これはオプションでコンパイラフラグでトリガーされます。クラスは別のライブラリにあり、ライブラリは名前空間の使用をオプションとしてユーザーに任せています。図書館)。ここGameでのクラスは、次のようになります(抜粋):

OAE_BEGIN_NAMESPACE

// forward-declarations:
class Player;    // Player is just another class in the same library

class Game : public QObject
{
    Q_OBJECT

public:
    explicit Game(...);

public slots:
    Player *player() const;  // <-- the quesion is about such slots
};

OAE_END_NAMESPACE

マクロは、Qtが実行するのと同じように、マクロ名で「QT」が「OAE」に置き換えられるだけで、 ...または何もOAE_BEGIN/END_NAMESPACE展開されません。namespace OAE_NAMESPACE {}<qglobal.h>

#ifndef OAE_NAMESPACE

# define OAE_PREPEND_NAMESPACE(name) ::name
# define OAE_USE_NAMESPACE
# define OAE_BEGIN_NAMESPACE
# define OAE_END_NAMESPACE
# define OAE_BEGIN_INCLUDE_NAMESPACE
# define OAE_END_INCLUDE_NAMESPACE
# define OAE_BEGIN_MOC_NAMESPACE
# define OAE_END_MOC_NAMESPACE
# define OAE_FORWARD_DECLARE_CLASS(name) class name;
# define OAE_FORWARD_DECLARE_STRUCT(name) struct name;
# define OAE_MANGLE_NAMESPACE(name) name

#else /* user namespace */

# define OAE_PREPEND_NAMESPACE(name) ::OAE_NAMESPACE::name
# define OAE_USE_NAMESPACE using namespace ::OAE_NAMESPACE;
# define OAE_BEGIN_NAMESPACE namespace OAE_NAMESPACE {
# define OAE_END_NAMESPACE }
# define OAE_BEGIN_INCLUDE_NAMESPACE }
# define OAE_END_INCLUDE_NAMESPACE namespace OAE_NAMESPACE {
# define OAE_BEGIN_MOC_NAMESPACE OAE_USE_NAMESPACE
# define OAE_END_MOC_NAMESPACE
# define OAE_FORWARD_DECLARE_CLASS(name) \
    OAE_BEGIN_NAMESPACE class name; OAE_END_NAMESPACE \
    using OAE_PREPEND_NAMESPACE(name);

# define OAE_FORWARD_DECLARE_STRUCT(name) \
    OAE_BEGIN_NAMESPACE struct name; OAE_END_NAMESPACE \
    using OAE_PREPEND_NAMESPACE(name);

# define OAE_MANGLE_NAMESPACE0(x) x
# define OAE_MANGLE_NAMESPACE1(a, b) a##_##b
# define OAE_MANGLE_NAMESPACE2(a, b) OAE_MANGLE_NAMESPACE1(a,b)
# define OAE_MANGLE_NAMESPACE(name) OAE_MANGLE_NAMESPACE2( \
        OAE_MANGLE_NAMESPACE0(name), OAE_MANGLE_NAMESPACE0(OAE_NAMESPACE))

namespace OAE_NAMESPACE {}

# ifndef OAE_BOOTSTRAPPED
# ifndef OAE_NO_USING_NAMESPACE
   /*
    This expands to a "using OAE_NAMESPACE" also in _header files_.
    It is the only way the feature can be used without too much
    pain, but if people _really_ do not want it they can add
    DEFINES += OAE_NO_USING_NAMESPACE to their .pro files.
    */
   OAE_USE_NAMESPACE
# endif
# endif

#endif /* user namespace */

以下で、「名前空間を有効にする」と言うときは、マクロを宣言したことを意味します。OAE_NAMESPACEこの場合は、値を使用しますoae

特に、このクラスのインスタンスと、アプリケーションのユーザーインターフェイスのQML内からPlayer返されたクラスにアクセスします。player()このために、私は次のようにクラスを登録します。

qmlRegisterType<Game>();
qmlRegisterType<Player>();

QMLフロントエンドに、QML内Gameで呼び出されるのインスタンスへのポインターを提供します。theGame

view.engine()->rootContext()->setContextProperty("theGame",
        QVariant::fromValue<Game*>(game));

QML内では、これを通常どおり使用します。小さな例では、player():のポインタアドレスを出力する必要があります。

Rectangle {
    width: 100; height: 100
    Component.onCompleted: console.log(theGame.player())
}

を設定したかどうかに応じて、次の結果が得られますOAE_NAMESPACE(ちなみに、ライブラリとそれを使用するアプリケーションの両方に同じ設定を使用しています)。

  • 名前空間を無効にすると、すべてが期待どおりに機能し、QMLによってポインタが出力されます。

    Player(0x10b4ae0)
    
  • 名前空間を有効にする場合(およびusingライブラリを使用するC ++コード内であるため、コードをまったく変更しません)、QMLは次の戻り値のタイプを理解できませんGame::player()

    Error: Unknown method return type: Player*
    
  • の戻りタイプをに変更するGame::player()oae::Player*、すべてが再び正常に機能します。

    oae::Player(0x10b4ae0)
    

これまでの私の結論はmoc、クラスの周りに配置した名前空間を考慮していないということです。私の最初の推測は次のとおりです。ねえ、moc呼び出し時に名前空間を定義することを知りませんg++。これは、.proファイルで行うことです。

DEFINES += OAE_NAMESPACE=oae

ただし、戻り値のタイプをに変更しOAE_NAMESPACE::Player*ても機能するため、mocはマクロを認識しますが、マクロを展開しないか、名前空間を解析しなくなります。OAE_NAMESPACEOAE_BEGIN/END_NAMESPACE

mocPlayer * Game::player() constメソッドの戻り型を含む次の「stringdata」を生成します。

  • 名前空間を無効にして戻りタイプを使用する場合Player*

    "player\0Player*\0"
    
  • 名前空間を有効にしてリターンタイプを使用する場合Player*

    "player\0Player*\0"
    
  • 名前空間を有効にしてリターンタイプを使用する場合OAE_NAMESPACE::Player*

    "player\0oae::Player*\0"
    

一方、有効になっている場合は、名前空間でmoc返されるクラス名を先頭に追加します。QMetaObject::className()

私の結論は、QObjectメタメソッドのシグニチャでこれらのタイプを使用する代わりに、書き込むことでこれを修正できるということです。(まあ、より良いマクロがあります)。これはコードではひどいように見えますが、メソッドがすでに名前空間にあるため、私には間違っているように見えるので、より良い解決策はありますか?OAE_NAMESPACE::ClassNameClassNameOAE_PREPEND_NAMESPACE

今はOAE_BEGIN/END_MOC_NAMESPACE(に類似しているQT_BEGIN/END_MOC_NAMESPACE)もあるので、多分私はどこかにそれらが必要ですか?Qtでどこでどのように使用されているかわからないので、Qtと同じオプションの名前空間機能を使用したいので、ライブラリでそれに応じて使用する必要があります。

4

1 に答える 1

8

5.0.0aで本当に機能しましたか?

Qt 5.0.0のソースコードを参照し、メソッドが解析される場所、特にリターンタイプ(fyi、5.0.0 \ qtbase \ src \ tools \ moc \ moc.cpp:L160)を調べましたが、名前空間チェックはありません(どちらも引数なので、player(Player* p)どちらも機能しません)。一方、クラスdef(5.0.0 \ qtbase \ src \ tools \ moc \ moc.cpp:L620&L635)に対して行われます。

「私たち」はこれをバグ(または見落とし)と呼ぶことができると思います

于 2013-01-11T12:58:04.723 に答える