QT_BEGIN_NAMESPACE or QT_FORWARD_DECLARE_CLASS best practice



  • I've been reading up on the QT_BEGIN_NAMESPACE define. I think I understand why it's used in code written for the qt library. I was looking at some example code and I notice it's used for forward declarations of classes. I'm wondering a couple of things

    1. Is doing this considered a best practice? Should all forward declarations of QT classes in my code be surrounded by the BEGIN/END defines?

    2. If QT were actually built inside a namespace would the examples really compile?

    Regarding question 2: While the forward declaration is now wrapped inside the namespace the use of the forward declaration is not. At least not in the examples I looked at. For example, in the loopback sample we have the following (elided) code:

    @QT_BEGIN_NAMESPACE
    ...
    class QProgressBar;
    ...
    QT_END_NAMESPACE@

    Then in the code
    @private:
    QProgressBar *clientProgressBar;@

    If QProgressBar were in namespace Foo:: the forward declaration at the top is fine but won't this declaration of a pointer to QProgressBar cause a compile error since there is no ::QProgressBar class?

    Should I be making all my Qt forward class references in the following form?
    @QT_FORWARD_DECLARE_CLASS(QProgressBar)@

    Is there documentation about QT_FORWARD_DECLARE_CLASS somewhere?



  • In my opinion, whether or not to use Qt libraries within a namespace is not something that you want to change casually over the course of the project. Decide early if you really need this. Then you'll need to configure and build Qt manually to wrap it inside a namespace. The pre-built binaries and Qt that comes with Linux distributions do not make use of this feature. It's really only and option for very large projects where you might want to isolate all 3rd party libraries into some namespace. But if you decide for it, the process is following:

    decide a namespace name, eg. MyQtLibs

    ./configure -qtnamespace MyQtLibs

    build your Qt libs

    And since you'll be using your custom Qt build, wrapped in a namespace, you'll declare Qt classes like this:

    @
    private:
    MyQtLibs::QProgressBar *progressBar;
    @

    IMHO, for most projects this is not really something you'll want to use, and therefore you can ignore these namespace macros. But if you are writing library code targeted for wide audience, then by all means, follow the principles as found in Qt's own headers.

    For the documentation of said macros, look in the qglobal.h, they are declared at the top of the file and it's pretty obvious what they do (and how to use them). If you configure and compile Qt with a namespace defined, expect the QT_NAMESPACE macro to be set to the name of your namespace passed to ./configure.



  • I guess I wasn't clear enough in my question, although I still find the feedback valuable. I'm not planning on rebuilding Qt in a namespace. I was wondering if was a best practice to write my code such that it is immune to Qt having been compiled in a namespace or not.

    Also the question about the examples using QT_BEGIN_NAMESPACE vs QT_FORWARD_DECLARE_CLASS will maybe be clearer with a specific example. In the activeqt\dotnet\wrapper\lib\tools.h (chosen at random because it was simple) you'll see the following:

    @QT_BEGIN_NAMESPACE
    class QString;
    QT_END_NAMESPACE

    System::String *QStringToString(const QString &qstring);
    QString StringToQString(System::String *string);

    #endif // TOOLS_H@

    I don't see how this would compile if Qt were actually in a namespace. The forward declaration of the class QString is correct but the usage as a parameter to QStringToString is not. After looking more at qglobal.h (not qtglobal.h btw), it looks to me like the example should be:
    @System::String *QStringToString(const QT_PREPEND_NAMESPACE(QString) &qstring);@

    This isn't an isolated example by the way. This seems to happen quite a bit in the examples. I just don't see how these examples are correct. The examples that use QT_FORWARD_DECLARE_CLASS do seem to be correct to me and also make the code less cluttered, or at least keep all the clutter in the forward declaration area. Of course this happens at the price of bringing all such names into scope,



  • If you want your library to be 100% correct and reusable, you probably don't want to mix Qt types into your namespace (or the global namespace). In that case you have to use QT_PREPEND_NAMESPACE on every occasion of using a Qt symbol. You are right that this clutters the code significantly. Doing this makes only sense in your library's public headers. In .cpp files you'll probably want to bring Qt in, using QT_USE_NAMESPACE, and only use QT_PREPEND_NAMESPACE to resolve name clashes.

    Personally I think there is little need to put Qt into a namespace, as Qt symbols start with Q/q" and distinguish themselves pretty well. This feature is there for the 0,01% of special cases. I keep saying, you should consider going through this trouble only when writing a library and expecting a very wide audience, where you might hit one of those special cases. In an end-user program, I would just bring the whole Qt in with QT_USE_NAMESPACE. In such case, I don't think that complete namespace isolation would make sense and would prefer code readability. Also, I haven't yet seen any Qt-based library, that would make use of this feature (and would compile if Qt is inside a namespace). Of course, the decision is yours. The ability to use your product with Qt in a namespace is a feature like any other feature. You should know, whether you or your audience will require it. If you are not sure, then I would say, don't bother and go with cleaner code.

    You are also right about the Qt samples. There might be an explanation for this: most people who custom-compile Qt, skip the compilation of samples to speed up the build. I doubt that even the commercial maintainer(s) do build the whole of Qt with every configuration combination.


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.