On Wed, 5 Nov 2025 at 14:05, Volker Hilsheimer <[email protected]> wrote:
>
>
>
> > On 5 Nov 2025, at 12:30, Ville Voutilainen <[email protected]> 
> > wrote:
> >
> > On Wed, 5 Nov 2025 at 12:11, Volker Hilsheimer via Development
> > <[email protected]> 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?
-- 
Development mailing list
[email protected]
https://lists.qt-project.org/listinfo/development

Reply via email to