QVersionNumber

What's New in Qt 5.6.0: QVersionNumber

By Jeff Tranter

The Qt 5.6.0 release, coming in early 2016, includes a number of new modules and classes. I plan to cover a number of these in a series of blog posts. In this first post, we'll start with one of the simpler classes in Qt 5.6.0: QVersionNumber.

Basics

Part of the Qt core, it provides a facility to manage version numbers. In this context, version numbers are defined as an arbitrary number of segments, which are numbers separated by dots or periods. A version can also have an arbitrary suffix added to the end.

The following are examples of valid version numbers for the QVersionNumber class:

    1.0
    1.2.3
    3.4.5.6.7
    1.2-alpha
    3.4-rc1

While it is supported by QVersionNumber, it is rare for software to use more than three levels of numbering. For convenience, the first three segments are referred to as major, minor and micro respectively.

The class has the concept of normalized versions, where trailing zeroes are removed. This allows version strings like 5.6 and 5.6.0, for example, to be considered equivalent.

Provided by the class are a number of constructors that can create an empty QVersionNumber, an instance given major, minor and/or micro versions, or even from a QVector or C++11 initializer list.

The class provides a number of useful methods to perform common functions such as getting the major version, normalizing, converting to a string and comparing two versions. It also provides suitable operators for comparison and QDataStream input and output.

The QVersionNumber class is for use from C++ only, no QML interface is offered.

Code Example

The following is a simple non-graphical Qt program which demonstrates some of the basic features of the QVersionNumber class. I encourage you to download the source code (1) and try it out yourself.

#include <QDebug>
#include <QCoreApplication>
#include <QVector>
#include <QVersionNumber>

/* Demonstration of QVersionNumber class. */

int main(int argc, char **argv)
{
    // Create a QCoreApplication and set the version property so we can later get it.
    QCoreApplication app(argc, argv);
    app.setApplicationVersion("1.2.3");

    // Demonstrate using the various constructors.
    QVersionNumber ver1 = QVersionNumber();
    QVersionNumber ver2 = QVersionNumber(1);
    QVersionNumber ver3 = QVersionNumber(1, 2);
    QVersionNumber ver4 = QVersionNumber(1, 2, 3);
    QVersionNumber ver5 = QVersionNumber(1, 2, 3);
    QVersionNumber ver6 = QVersionNumber::fromString("1.2.3");
    QVersionNumber ver7 = QVersionNumber({1, 2, 4}); // C++11 initializer list

    QVector<int> vec;
    vec << 1 << 2 << 3;
    QVersionNumber ver8 = QVersionNumber(vec);

    // Qt version
    QVersionNumber verQt = QVersionNumber::fromString(QT_VERSION_STR);
    // Application version
    QVersionNumber verApp = QVersionNumber::fromString(app.applicationVersion());

    qDebug() << "ver1 =" << ver1;
    qDebug() << "ver2 =" << ver2;
    qDebug() << "ver3 =" << ver3;
    qDebug() << "ver4 =" << ver4;
    qDebug() << "ver5 =" << ver5;
    qDebug() << "ver6 =" << ver6;
    qDebug() << "ver7 =" << ver7;
    qDebug() << "ver8 =" << ver8;
    qDebug() << "verQt =" << verQt;
    qDebug() << "verApp =" << verApp;

    qDebug() << "ver1 is normalized?" << (ver1.isNormalized() ? "yes" : "no");
    qDebug() << "ver2 is normalized?" << (ver2.isNormalized() ? "yes" : "no");
    qDebug() << "ver1 is null?" << (ver1.isNull() ? "yes" : "no");
    qDebug() << "ver2 is null?" << (ver2.isNull() ? "yes" : "no");
    qDebug() << "ver3 is prefix of ver4?" << (ver3.isPrefixOf(ver4) ? "yes" : "no");
    qDebug() << "ver4 major version:" << ver4.majorVersion();
    qDebug() << "ver4 minor version:" << ver4.minorVersion();
    qDebug() << "ver4 micro version:" << ver4.microVersion();
    qDebug() << "ver3 normalized:" << ver3.normalized();
    qDebug() << "ver4 normalized:" << ver4.normalized();
    qDebug() << "ver4 segment count:" << ver4.segmentCount();
    qDebug() << "ver4 segment at 0:" << ver4.segmentAt(0);
    qDebug() << "ver4 segment at 1:" << ver4.segmentAt(1);
    qDebug() << "ver4 segment at 2:" << ver4.segmentAt(2);
    qDebug() << "ver4 segments:" << ver4.segments();
    qDebug() << "ver4 to string:" << ver4.toString();
    qDebug() << "ver4 ver5 common prefix:" << QVersionNumber::commonPrefix(ver4, ver5);
    qDebug() << "ver6 ver7 common prefix:" << QVersionNumber::commonPrefix(ver6, ver7);
    qDebug() << "ver4 ver5 compare:" << QVersionNumber::compare(ver4, ver5);
    qDebug() << "ver6 ver7 compare:" << QVersionNumber::compare(ver6, ver7);

    qDebug() << "ver4 != ver5:" << (ver4 != ver5 ? "yes" : "no");
    qDebug() << "ver4 < ver5:" << (ver4 < ver5 ? "yes" : "no");
    qDebug() << "ver4 <= ver5:" << (ver4 <= ver5 ? "yes" : "no");
    qDebug() << "ver4 == ver5:" << (ver4 == ver5 ? "yes" : "no");
    qDebug() << "ver4 > ver5:" << (ver4 > ver5 ? "yes" : "no");
    qDebug() << "ver4 >= ver5:" << (ver4 >= ver5 ? "yes" : "no");

    ver4 = ver5; // Assignment operator

    return 0;
}

Summary

In Qt 5.6.0, Qt uses the QVersionNumber class internally in a few places, but not in any public APIs. Possibly in the future Qt will make more use of the class. I can imagine for example, having a method that returns the Qt version as a QVersionNumber or perhaps the QCoreApplication applicationVersion property. The QDataStream class has support for version numbering that could possibly use this new class, although it would need to do so in a way that remained binary compatible.

In summary, the new QVersionNumber class is quite easy to use and the documentation explains it in detail.

Note that this blog post was based on the Qt 5.6.0 beta version and changes may still occur before final 5.6.0 release.

References

  1. Example application source code, accessed 3 December 2015, ftp://ftp.ics.com/pub/pickup/versionnumber.zip
  2. QVersionNumber Class, Qt Reference Documentation, accessed 3 December 2015, https://doc-snapshots.qt.io/qt5-5.6/qversionnumber.html