[Development] parented_ptr
Volker Hilsheimer
volker.hilsheimer at qt.io
Thu Nov 6 15:39:54 CET 2025
> On 5 Nov 2025, at 19:07, Ville Voutilainen <ville.voutilainen at gmail.com> wrote:
>
> On Wed, 5 Nov 2025 at 14:05, Volker Hilsheimer <volker.hilsheimer at qt.io> wrote:
>>
>>
>>
>>> On 5 Nov 2025, at 12:30, Ville Voutilainen <ville.voutilainen at gmail.com> wrote:
>>>
>>> On Wed, 5 Nov 2025 at 12:11, Volker Hilsheimer via Development
>>> <development at qt-project.org> wrote:
>>>> And again, we need to make sure that object->createChild<QWidget>() is not possible; from what I see, that can be solved via SFINAE:
>>>>
>>>> class QObject …
>>>> {
>>>> template <typename ChildType, typename ...Args,
>>>> std::enable_if_t<!std::is_base_of_v<QWidget, ChildType>, bool> = true
>>>>>
>>>> ChildType *makeChild(Args &&...args)
>>>> {
>>>> return new ChildType(std::forward<Args>(args)..., this);
>>>> }
>>>> };
>>>>
>>>> (it’s enough for QWidget to be forward declared, which it is already in qobject.h)
>>>>
>>>> and then overloading this in QWidget without the constraint (a QObject can be a child of a QWidget).
>>>
>>> I don't quite follow why you think you need any SFINAE for this. If
>>> you try to construct a QWidget child with a
>>> QObject::createChildObject(),
>>> that will fail to compile anyway because it tries to pass a QObject*
>>> parent to the QWidget constructor, and that
>>> constructor takes a QWidget*. There is no implicit base*->derived* conversion.
>>
>>
>> “fails to compile” != “fails to compile and produces a meaningful error message”
>>
>>
>> Without SFINAE:
>>
>> /Users/vohi/qt/dev/qtbase/src/corelib/kernel/qobject.h:354:20: error: no matching constructor for initialization of 'QLineEdit'
>> 354 | return new ChildType(std::forward<Args>(args)..., this);
>> | ^ ~~~~
>> /Users/vohi/qt/dev/qtbase/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp:14209:12: note: in instantiation of function template specialization 'QObject::makeChild<QLineEdit>' requested here
>> 14209 | object.makeChild<QLineEdit>();
>> | ^
>> /Users/vohi/qt/dev/qtbase/src/widgets/widgets/qlineedit.h:58:14: note: candidate constructor not viable: cannot convert from base class pointer 'QObject *' to derived class pointer 'QWidget *' for 1st argument
>> 58 | explicit QLineEdit(QWidget *parent = nullptr);
>
> Right, here.
>
>> | ^ ~~~~~~~~~~~~~~~~~~~~~~~~~
>> /Users/vohi/qt/dev/qtbase/src/widgets/widgets/qlineedit.h:59:14: note: candidate constructor not viable: no known conversion from 'QObject *' to 'const QString' for 1st argument
>> 59 | explicit QLineEdit(const QString &, QWidget *parent = nullptr);
>> | ^ ~~~~~~~~~~~~~~~
>> /Users/vohi/qt/dev/qtbase/src/widgets/widgets/qlineedit.h:216:20: note: candidate constructor not viable: no known conversion from 'QObject *' to 'const QLineEdit' for 1st argument
>> 216 | Q_DISABLE_COPY(QLineEdit)
>> | ~~~~~~~~~~~~~~~^~~~~~~~~~
>> /Users/vohi/qt/dev/qtbase/src/corelib/global/qtclasshelpermacros.h:24:5: note: expanded from macro 'Q_DISABLE_COPY'
>> 24 | Class(const Class &) = delete;\
>> | ^ ~~~~~~~~~~~~~
>> 1 error generated.
>> ninja: build stopped: subcommand failed.
>>
>>
>> (probably multiplied by number of constructors of the ChildType you wanna instantiate, as the compiler will try each of them).
>>
>>
>> With SFINAE:
>>
>> /Users/vohi/qt/dev/qtbase/tests/auto/widgets/kernel/qwidget/tst_qwidget.cpp:14209:12: error: no matching member function for call to 'makeChild'
>> 14209 | object.makeChild<QLineEdit>();
>> | ~~~~~~~^~~~~~~~~~~~~~~~~~~~
>> /Users/vohi/qt/dev/qtbase/src/corelib/kernel/qobject.h:354:16: note: candidate template ignored: requirement '!std::is_base_of_v<QWidget, QLineEdit>' was not satisfied [with ChildType = QLineEdit, Args = <>]
>> 354 | ChildType *makeChild(Args &&...args)
>
> Do you expect to SFINAE away also QWindow and QGraphicsItem and other
> types, too?
>
> Why use an enable_if instead of static_assert?
As the mailing list doesn’t make for a great code review experience: https://codereview.qt-project.org/c/qt/qtbase/+/689322
Good catch with QWindow (and possibly other types for which we explictly overload setParent to require something else than QObject *); QGraphicsItem is not a QObject.
Cheers,
Volker
More information about the Development
mailing list