[Development] How to include Standard Library headers from Qt ones?

Marc Mutz marc.mutz at kdab.com
Sat Apr 15 15:56:14 CEST 2017


On Saturday 15 April 2017 14:40:40 Giuseppe D'Angelo wrote:
> Il 15/04/2017 08:15, Marc Mutz ha scritto:
> > On Saturday 15 April 2017 00:49:35 Giuseppe D'Angelo wrote:
> >> * Q_DECLARE_TYPEINFO over suitable Standard Library datatypes;
> > 
> > I can only think of std::pair here, and it's done already, in
> > qhashfunctions.h
> > 
> > Specifically, we can say nothing about any of the std containers, as they
> > are free to choose their own implementation. E.g. a std::string with SSO
> > is not trvially relocatable.
> > 
> > std::pair is special, since the standard prescibes a layout for it.
> 
> There may be others: std::complex comes to mind; or maybe std::array; or
> maybe other stuff that's going to be added later. We got a Get Out of
> Jail Free card with std::pair because <utility> was already included
> from qglobal.h, what do we do for the others?
> 
> >> * defining qHash over suitable Standard Library datatypes;
> > 
> > This is the hard one. One could come up with wrappers for each std
> > header, and add qHash() there, but realisically, I don't think it's
> > worth it. If you have std keys, use std types.
> > 
> > This dependency inversion is yet another reason to stop providing std
> > facilities in Qt (as soon as we realistically can).
> 
> This is kind of a harsh resolution.
>
> Are people fine with it? The danger
> is of course downstreams defining their own qHash(std::...) all over the
> place. And we can't universally recommend unordered associative
> containers from std (or even deprecate QHash!) because of the next point...
>
> >> * defining std::hash specializations for suitable Qt datatypes;
> > 
> > This is simple, from a header pov: you only need to #include
> > <functional>.
> 
> I definitely think std::hash specializations should be added for all
> suitable types; and mandating a specialization of std::hash should also
> be part of the coding policies. Yet, how many datatypes in Qt offer
> std::hash right now?

Well, we don't really know, yet, if all of our supported platforms support 
std::hash. Being a specialisation, someone needs to provide the primary 
template...

I'm hoping that we *can* depend on std:hash being available by now. The 
problem, of course, is QNX.
 
> > The problem here is that, absent std::basic_string_view, you have no way
> > to hash arbitrary memory (without first constructing a std::string, that
> > is).
> > 
> > The underlying issue is that any user-specialisation of std::hash should
> > delegate to a stdlib-provided one, because implementations are free to
> > add seeding, and, lacking an extra argument, the only way to incorporate
> > the seed is to call a library-provided specialisation.
> > 
> > So while it's trivial to add std::hash specialisations for something like
> > QVector, QSizePolicy or QPoint (but not QPointF, because its op== is
> > broken), I currently don't see how we could add them for QString or
> > QByteArray, at least without looping over std::hash<char>, which imo is
> > a no-no.
> 
> Not to mention that
> * combining the results of looping over std::hash<char> may well not
> yeild the same results of applying std::hash<string_view> over the whole
> sequence;

That's a SEP.

The standard, unlike Qt, allows to pass user-defined hashing functions 
everywhere they are used, so it's trivial to define your own hashing function 
and use it. The main problem with qHash() is that there's _only_ qHash(), and 
nothing else.

> * there isn't a hash combiner in the std (so we'd still be needing ours);

It's not "ours", it's boost::hash_combine :) And we can't use it, because it 
calls qHash() instead of taking a hash function as a parameter. But we can use 
boost::hash_combine if we finally get over it and just use it instead of 
reimplementing everything from boost all over.

> * it's not guaranteed that the hashing algorithm used by std::hash on a
> type's internal representation is also the best algorithm for the values
> that that type can actually represent (but rolling your own algorithm,
> and not using std::hash, makes you lose the seeding or any other goodies
> done by the implementation). There's a huge discussion in N3980.

I know Howard's ideas about hashing, and I agree with them. In Qt, we largely 
ignore the issue of hash collisions for a given type and just hash its 
members, combining with boost::hash_combine, and hope for the best. As such, 
the problem described in Paragraph 5 of 
https://isocpp.org/files/papers/n3980.html#Solution1B, if it is, indeed, the 
one you're referring to, is the same for qHash() and std::hash. Only a 
Hinnant-like hashing interface that takes the hash function as a parameter 
would solve that.

Are you suggesting to skip supporting std::hash and go directly to providing 
Hinnant's interface in Qt instead?

Thanks,
Marc

-- 
Marc Mutz <marc.mutz at kdab.com> | Senior Software Engineer
KDAB (Deutschland) GmbH & Co.KG, a KDAB Group Company
Tel: +49-30-521325470
KDAB - The Qt, C++ and OpenGL Experts



More information about the Development mailing list