[Development] QList
Marc Mutz
marc.mutz at kdab.com
Sat Mar 25 18:22:22 CET 2017
On Saturday 25 March 2017 16:29:09 Thiago Macieira wrote:
> On sábado, 25 de março de 2017 00:57:57 PDT Marc Mutz wrote:
> > On 2017-03-24 20:55, Thiago Macieira wrote:
> > > Em sexta-feira, 24 de março de 2017, às 09:18:05 PDT, Marc Mutz
> > > escreveu:
> > >> > Are you of the opinion that private inheritance has no purpose and
> > >> > should
> > >> > never be used?
> > >>
> > >> No, and if you look at code I have written over the years, you will
> > >> see that
> > >> I do use it.
> > >>
> > >> One thing I've looked into in the past is this: Q6Polygon should
> > >> inherit a
> > >> Q6VectorBase<QPoint> that also Q6Vector<QPoint> inherits. This will
> > >> allow
> > >> easy specialisation of QVector<T*> by inheriting QBasicVector<const
> > >> void*>.
> > >
> > > Can you elaborate on your thinking? What's QBasicVector and what's
> > > QVector?
> >
> > QBasicVector (or QVectorBase, or ...) is QVector with protection against
> > using it as-is (e.g. protected dtor). QVector inherits QBasicVector to
> > lift the restriction. This inheritance may even be public to avoid lots
> > of using QBasicVector::foo; This is ok, because QBasicVector is not
> > usable as-is, but I'd still make it private, because when you start to
> > inherit to specialise (QVector<T*> : QBasicVector<const void*>), you
> > don't want the void* methods to leak.
> >
> > So, if you absolutely are set on inheritance, then use the same pattern.
> > But I don't see this here. None of the points that makes this a good
> > idea for QVector (or QVLA) pertains to QString: we don't need to fight
> > template bloat, we don't have multiple classes inheriting QStringView...
>
> And what are the points that make QBasicVector good? If QBasicVector is not
> usable as-is, then it must be useful because it's sharing code between
> QVector and something else. What is that something else?
The main idea of QBasicVector is to fight template bloat by e.g. inheriting
both QVector<const T> and QVector<T> from the same QBasicVector. Likewise, all
QVector<T*> can inherit QBasicVector<const void*>. Or all QVector<T>,
intergral_type<T> can inherit QBasicVector<QIntegerForSizeof<T>::Unsigned>, or
all QVector<E>, is_enum<E>, from
QBasicVector<QIntegerForSizeof<underlying_type_t<T>>::Unsigned>, or even
QVector<T>, qt_is_refcounted<T> && sizeof(T) == sizeof(void*) :
QBasicVector<QExplicitlySharedDataPointer<QSharedData>>...
You can do this with composition, too. You don't even need QBasicVector. But
if you e.g. want to collapse all QV<T*> to QV<const void*>, you need to either
manually specialise QV<const void*> or use SFINAE so the T* case does not
match const void*. Then you can aggregate a QV<const void*> in QV<T*> and
delegate all functions there.
With a separate QBasicVector, however, you don't need that special-casing of
const void*, or any of the other basic instantiated types, since the type
where you partially specialise is different from the implementation type.
You can also generally have QVector<T> _contain_ a QBasicVector<T>, and do the
specialisation via a type trait:
template <typename T>
class QVector {
using underlying_t = typename qvector_choose_underlying_for<T>::type;
QBasicVector<underlying_t> impl;
T* begin() { return reinterpret_cast<T*>
(const_cast<std::remove_cv_t<underlying_t>*>
(impl.begin())); }
// ...
}
template <typename T>
struct qvector_choose_underlying_for : std::add_const<T> {};
template <typename T, std::enable_if_t<std::is_enum_v<T>, bool> = false>
struct qvector_choose_underlying_for<E>
: qvector_choose_underlying_for<std::underlying_t<E>> {};
// ...
There are lots of options here, too. But if you throw extern templates into
the mix, it probably pays off if QVector<T>::reserve() _is_
QBasicVector<underlying_t<T>>::reserve(), meaning inheritance, so that the
compiler need not instantiate a delegating function but directly hits the
extern template declaration for QBasicVector.
I have no idea how that plays with inlining, though. Maybe in the end this
also turns into a case for using free functions to control inlining better.
I also have not thought this through.
But all that said, all this specialisation stuff, all the types that want to
inherit QVector because they are some form of collection of things, with no or
little constraints added, and all these not-yet-mentioned uses of QBV to
implement fast conversion from, say, QPolygon to QVector<QPoint>, even though
they are unrelated, these all do not apply to QString.
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