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
