Qt6 C++ compilation changes
-
I am moving existing code which compiles fine under Qt5.15, gcc 11.4.0,
-std=gnu++1z
(C++17) to Qt6, gcc 13.2.0, also-std=gnu++1z
.I have a couple of errors in new Qt6 vs Qt5 compilation for which I would like to know the actual reason. I have a correction/workaround in each case but I should still like to understand what the difference is to improve my C++ knowledge. It happens that both of these relate to "implicit type conversion" rules which I clearly don't know fully.
First
qsizetype
:std::max(function_returning_qsizetype(), 10) >> error: no matching function for call to ‘max(qsizetype, int)’
I now have change to:
std::max(function_returning_qsizetype(), 10LL)
Why did
10
used to work but now requires10LL
? Note thatqsizetype st{10} /* or st(10) */; std::max(function_returning_qsizetype(), st)
works, so at some level we can assign
10
to aqsizetype
.Second
QFlags<...>
toQVariant
:
Returning a value fromQVariant QAbstractItemModel::data()
case Qt::TextAlignmentRole: return Qt::AlignHCenter | Qt::AlignVCenter; >> could not convert ‘Qt::operator|(Qt::AlignHCenter, Qt::AlignVCenter)’ from ‘QFlags<Qt::AlignmentFlag>’ to ‘QVariant’
Note that:
QFlags<Qt::AlignmentFlag> fl(Qt::AlignHCenter | Qt::AlignVCenter); return fl;
doesn't help, same error on
return
statement.I now have change to:
return QVariant(Qt::AlignHCenter | Qt::AlignVCenter);
Why do I now need to cast/construct explicitly? Also why does
return Qt::AlignCenter;
work OK (without
QVariant(...)
) given the definition isenum AlignmentFlag { ... AlignCenter = AlignVCenter | AlignHCenter }; Q_DECLARE_FLAGS(Alignment, AlignmentFlag)
-
Wrt std::max():
std::max() is a template :
template< class T > const T& max( const T& a, const T& b );
As you can see both a and b must be of the same type.
10
is an int32_t by design. qsizetype is std::ssize_t which is 64 bit on 64bit platforms. So the real question here is - why did it work with Qt5. Did you use 32 bit there?Wrt to QFlags:
I would guess there was an implicit conversion to uint in Qt5 for QFlags<T> which was removed. Maybe now QT_TYPESAFE_FLAGS is defined by default to avoid this conversion.
-
why did it work with Qt5. Did you use 32 bit there?
Absolutely not, 64-bit.
Was
qsizetype
defined asstd::ssize_t
at Qt5, did it change subtly at Qt6?If not, gcc version has been upped (per my initial post) at my new Ubuntu 24.04, it might be that?
I still don't totally understand that e.g.
int
s (like an unqualified literal number) matchlong
s but seemingly notlong long
s.It's a pain to have to change literals like
10
to10LL
to usestd::max()
. Most Qt classes withcount()
/size()
(likeQList
) returnqsizetype
/long long
and will require this of me now/for existing code. -
@JonB said in Qt6 C++ compilation changes:
Was qsizetype defined as std::ssize_t at Qt5, did it change subtly at Qt6?
No, see the docs: https://doc.qt.io/qt-5/qtglobal.html#qsizetype-alias
-
qsizetype
is used for container indexing and that DID change in Qt 6. In Qt 5 containers returnedsize()
asint
(so 32 bit on most platforms).But if your function really retuned
qsizetype
in Qt 5 then I'm not entirely sure what's the deal. -
@sierdzio
Thanks, this sparked me to investigate. I happened to be usingQJsonArray::count()
as the function being passed tostd::max(jsonArray.count(), 10)
.- https://doc.qt.io/qt-5/qjsonarray.html#count:
int QJsonArray::count() const
- https://doc.qt.io/qt-6/qjsonarray.html#count:
qsizetype QJsonArray::count() const
So at Qt6 it changed from
int
toqsizetype
. This also answers @Christian-Ehrlicher as to why (without me being 32-bit). Hence the error at Qt6 but not at Qt5.....Now then. This change has been made throughout Qt6, e.g.
QList::count()
has moved fromint
toqsizetype
similarly. That means potentially I will have a number of similar issues as & when I move other code from Qt5 to Qt6.... :([BTW: Searching for changes from Qt5 to Qt6. I have no trouble finding lists of new or removed functions. I am unable to find where changes are documented for existing functions, such as this change in return types? Anywhere.]
- https://doc.qt.io/qt-5/qjsonarray.html#count:
-
@JonB said in Qt6 C++ compilation changes:
Searching for changes from Qt5 to Qt6
here's my checklist what I found out while porting (mobile) apps from 5.15 to 6.7:
https://t1p.de/ekkeChecklist -
QList's (and hence QVector's) size type is changed from int to qsizetype. Together with the size type, all relevant methods' signatures are updated to use qsizetype. This allows QList to hold more than 2^31 items on 64 bit platforms.
-
@JonB said in Qt6 C++ compilation changes:
std::max(function_returning_qsizetype(), 10LL)
Using
10LL
is not portable. I don't really remember which type had this problem, but I once ran into a problem with these integer literals that did not have a solution for Windows, Linux, and macOS (yet). Starting from C++23 you haveZ
available which will be actually be portable for this use case (https://en.cppreference.com/w/cpp/language/integer_literal). -
@SimonSchroeder
What a mess trying to find a simple literal of the same type as something as basic as whatQList::count()
returns!For my part I only have to support gcc.
I shan't be writing
for (qsizetype i = 0LL; i < list.count()
, I will be sticking withint
. So one possibility would be to convert/cast theqsizetype
toint
for thestd::max()
so I can use a plain literal. But I think I will abandonstd::max()
forqMax()
to avoid this ugliness. -
I shan't be writing
for (qsizetype i = 0LL; i < list.count()
, I will be sticking withint
.It might fail for very large lists ;-) But
for (qsizetype i = 0; i < list.count()
should work just fine.As for max, this is also an option if you like to type a lot:
std::max(jsonArray.count(), static_cast<qsizetype>(10)).
-
@sierdzio said in Qt6 C++ compilation changes:
It might fail for very large lists
Absolutely! But as you can see the kind of size I have in mind is
10
. That is a long way away from2 ^ 63
:)static_cast<qsizetype>(10)
Of course! But I am simply not prepared to write to write that when comparing against
10
! -
@JonB This change matches the one in C++. I used to have loops like
std::vector< something > vec; for ( unsigned idx = 0; idx < vec.size(); ++idx ) { }
In new C++
std::vector< something > vec; for ( size_t idx = 0; idx < vec.size(); ++idx ) { }
If you do not like the casting, I guess you can replace your loop with
for ( auto const & element : your list ) { }
Simpler.
-
@JoeCFD
I object to usingsize_t
(should really bessize_t
which is whatqsizetype
is) as my "default" loop counter type when I have thousands of existing occurrences usingint
! (Having said that, just to be clear, the change in type/size does not prevent me from usingint
even now, so I don't have to change everything. It is something likestd::max()
which is affected/falls foul of the new definition.)Your last case is more or less what I use when iterating and I do not need the index inside the loop. But the integral counter is required/easier when you do need to know the index value.
-
@JonB from here
size(C++17)
ssize(C++20)
Something new for me. Good to know.https://en.cppreference.com/w/cpp/iterator/size
Recently I built a project on Windows with C++ 14. size_t is needed to replace int for std::vector in the build warnings.
when you need an index
int index{}; (if you prefer int) for ( auto const & element : your list ) { do something with index index++; }
-
@JoeCFD
Sorry if you think I am being difficult, but I'm not going to write a "for-element-in-list" loop and then maintain a separate index counter! One or the other!Besides I was talking about existing code already written. But as a I say I can still use an
int
loop counter at Qt6, at least with gcc, without warning. It's just something likestd::max()
which barfs.We can debate further if you wish, but I do get that Qt etc. need to change to
long long
for size/count/array-indexing etc. I just don't like how messy it is making it (forstd::max()
at least) to pass a simple, numeric, non-qualified literal.