diff --git a/public/og/moc-parity-matrix-reflection.png b/public/og/moc-parity-matrix-reflection.png index d4a95c0..06115dd 100644 Binary files a/public/og/moc-parity-matrix-reflection.png and b/public/og/moc-parity-matrix-reflection.png differ diff --git a/social/facebook/moc-parity-matrix-reflection/caption.md b/social/facebook/moc-parity-matrix-reflection/caption.md index 168a811..cd35938 100644 --- a/social/facebook/moc-parity-matrix-reflection/caption.md +++ b/social/facebook/moc-parity-matrix-reflection/caption.md @@ -1,7 +1,7 @@ -# Replacing moc with reflection: 29 of 47 matrix rows match, and a class needs no macro +# Replacing moc with reflection: 32 of 48 matrix rows match, and a class needs no macro ## Body -I listed 47 things moc does and tested each one against a real moc twin. 29 are the same (24 checked against a real moc), and a Qt class or a gadget now needs no macro at all. The open rows each have a stated reason. +I listed 48 things moc does and tested each one. 32 are the same (27 checked against a real moc), and a Qt class or a gadget now needs no macro at all. The open rows each have a stated reason. https://wrocpp.github.io/posts/moc-parity-matrix-reflection/ @@ -9,7 +9,7 @@ https://wrocpp.github.io/posts/moc-parity-matrix-reflection/ #cpp #cpp26 #qt #moc #wrocpp ## Alt-text -wro.cpp card with the magnet logo. Headline reads "A Qt class with no macro and no moc" with a subtitle about 29 of 47 rows of a moc conformance matrix being the same, 24 checked against a real moc. Citation footer: wro.cpp, 2026-10-29. +wro.cpp card with the magnet logo. Headline reads "A Qt class with no macro and no moc" with a subtitle about 32 of 48 rows of a moc conformance matrix being the same, 27 checked against a real moc. Citation footer: wro.cpp, 2026-10-29. ## Suggested post time Thursday 2026-10-29, 16:00 UTC diff --git a/social/facebook/moc-parity-matrix-reflection/content.md b/social/facebook/moc-parity-matrix-reflection/content.md index 3712b23..25edc50 100644 --- a/social/facebook/moc-parity-matrix-reflection/content.md +++ b/social/facebook/moc-parity-matrix-reflection/content.md @@ -6,7 +6,7 @@ template: social/linkedin-post :::insight{citation="wro.cpp -- 2026-10-29"} # A Qt class with no macro and no moc -29 of 47 rows of a moc conformance matrix are the same, each with a test, and 24 are checked against a real moc. The 11 unsupported rows each carry a reason. +32 of 48 rows of a moc matrix are the same, 27 checked against a real moc. Each of the 10 unsupported rows has a reason. ::: :::: diff --git a/social/facebook/moc-parity-matrix-reflection/image.png b/social/facebook/moc-parity-matrix-reflection/image.png index 4c1ec40..d692201 100644 Binary files a/social/facebook/moc-parity-matrix-reflection/image.png and b/social/facebook/moc-parity-matrix-reflection/image.png differ diff --git a/social/facebook/moc-parity-matrix-reflection/index.html b/social/facebook/moc-parity-matrix-reflection/index.html index 1ec36cf..c67846f 100644 --- a/social/facebook/moc-parity-matrix-reflection/index.html +++ b/social/facebook/moc-parity-matrix-reflection/index.html @@ -23,6 +23,6 @@ -

A Qt class with no macro and no moc

29 of 47 rows of a moc conformance matrix are the same, each with a test, and 24 are checked against a real moc. The 11 unsupported rows each carry a reason.

wro.cpp -- 2026-10-29
ScudoAI
AI-generated
+

A Qt class with no macro and no moc

32 of 48 rows of a moc matrix are the same, 27 checked against a real moc. Each of the 10 unsupported rows has a reason.

wro.cpp -- 2026-10-29
ScudoAI
AI-generated
\ No newline at end of file diff --git a/social/linkedin/moc-parity-matrix-reflection/caption.md b/social/linkedin/moc-parity-matrix-reflection/caption.md index 79f4dd5..ae90404 100644 --- a/social/linkedin/moc-parity-matrix-reflection/caption.md +++ b/social/linkedin/moc-parity-matrix-reflection/caption.md @@ -1,7 +1,7 @@ -# Replacing moc with reflection: 29 of 47 matrix rows match, and a class needs no macro +# Replacing moc with reflection: 32 of 48 matrix rows match, and a class needs no macro ## Body -I wrote down 47 things moc processes or generates, one row each, and tested every verdict. A "same" row builds the class for real moc next to the reflect-moc version and compares the two meta-objects row for row, then runs both. 29 rows are the same (24 checked against a real moc, 5 by behaviour moc cannot give), 5 differ in a way the note names, and 11 are not supported yet. +I wrote down 48 things moc processes or generates, one row each, and tested every verdict. A "same" row builds the class for real moc next to the reflect-moc version and compares the two meta-objects row for row, then runs both. 32 rows are the same (27 checked against a real moc, 5 by behaviour moc cannot give), 4 differ in a way the note names, and 10 are not supported yet. A Qt class, a derived class, a widget class and a gadget now need no macro and no moc input. The base class finds the class it belongs to through a default template argument, so the class is never named twice. @@ -13,7 +13,7 @@ https://wrocpp.github.io/posts/moc-parity-matrix-reflection/ #cpp #cpp26 #reflection #qt #moc #wrocpp ## Alt-text -wro.cpp card with the magnet logo. Headline reads "A Qt class with no macro and no moc" with a subtitle about 29 of 47 rows of a moc conformance matrix being the same, 24 checked against a real moc. Citation footer: wro.cpp, 2026-10-29. +wro.cpp card with the magnet logo. Headline reads "A Qt class with no macro and no moc" with a subtitle about 32 of 48 rows of a moc conformance matrix being the same, 27 checked against a real moc. Citation footer: wro.cpp, 2026-10-29. ## Suggested post time Thursday 2026-10-29, 16:00 UTC diff --git a/social/linkedin/moc-parity-matrix-reflection/content.md b/social/linkedin/moc-parity-matrix-reflection/content.md index 3712b23..25edc50 100644 --- a/social/linkedin/moc-parity-matrix-reflection/content.md +++ b/social/linkedin/moc-parity-matrix-reflection/content.md @@ -6,7 +6,7 @@ template: social/linkedin-post :::insight{citation="wro.cpp -- 2026-10-29"} # A Qt class with no macro and no moc -29 of 47 rows of a moc conformance matrix are the same, each with a test, and 24 are checked against a real moc. The 11 unsupported rows each carry a reason. +32 of 48 rows of a moc matrix are the same, 27 checked against a real moc. Each of the 10 unsupported rows has a reason. ::: :::: diff --git a/social/linkedin/moc-parity-matrix-reflection/image.png b/social/linkedin/moc-parity-matrix-reflection/image.png index d4a95c0..06115dd 100644 Binary files a/social/linkedin/moc-parity-matrix-reflection/image.png and b/social/linkedin/moc-parity-matrix-reflection/image.png differ diff --git a/social/linkedin/moc-parity-matrix-reflection/index.html b/social/linkedin/moc-parity-matrix-reflection/index.html index 1ec36cf..c67846f 100644 --- a/social/linkedin/moc-parity-matrix-reflection/index.html +++ b/social/linkedin/moc-parity-matrix-reflection/index.html @@ -23,6 +23,6 @@ -

A Qt class with no macro and no moc

29 of 47 rows of a moc conformance matrix are the same, each with a test, and 24 are checked against a real moc. The 11 unsupported rows each carry a reason.

wro.cpp -- 2026-10-29
ScudoAI
AI-generated
+

A Qt class with no macro and no moc

32 of 48 rows of a moc matrix are the same, 27 checked against a real moc. Each of the 10 unsupported rows has a reason.

wro.cpp -- 2026-10-29
ScudoAI
AI-generated
\ No newline at end of file diff --git a/src/content/posts/2026-10-29-moc-parity-matrix-reflection.mdx b/src/content/posts/2026-10-29-moc-parity-matrix-reflection.mdx index 079cc80..3989e86 100644 --- a/src/content/posts/2026-10-29-moc-parity-matrix-reflection.mdx +++ b/src/content/posts/2026-10-29-moc-parity-matrix-reflection.mdx @@ -1,5 +1,5 @@ --- -title: "Replacing moc with reflection: 29 of 47 matrix rows match, and a class needs no macro" +title: "Replacing moc with reflection: 32 of 48 matrix rows match, and a class needs no macro" slug: "moc-parity-matrix-reflection" pubDate: 2026-10-29 author: filip-sajdak @@ -9,7 +9,7 @@ series: cpp26-reflection series_order: 41 audience: working-cpp tags: [reflection, cpp26, qt, moc, testing, ai] -summary: "I listed 47 things moc processes or generates and gave each a verdict that a test must back. 29 rows are the same: 24 against a real moc's output, 5 by behaviour that moc cannot give. 5 differ in a stated way and 11 are not supported yet. A Qt class and a gadget now need no macro, because the base class finds the class through a default template argument." +summary: "I listed 48 things moc processes or generates and gave each a verdict that a test must back. 32 rows are the same: 27 against a real moc's output, 5 by behaviour that moc cannot give. 4 differ in a stated way and 10 are not supported yet. A Qt class and a gadget now need no macro, because the base class finds the class through a default template argument." draft: false relatedPosts: [regenerate-qt-containers-from-a-spec, qt-model-edge-cases-catalogue, qt-class-template-typed-signals-without-moc, qt-object-that-never-names-its-class] --- @@ -18,8 +18,8 @@ import PostLink from '../../components/PostLink.astro'; ## In short -- The question was how much of moc reflection replaces. I wrote 47 rows, one per construct, each with a verdict and a test. -- 29 rows are "same". In 24 of them the meta-object equals a real moc's, and the behaviour matches. The other 5 have no twin. 5 rows are partial, 11 are unsupported, 1 needs a build step and 1 is not needed. +- The question was how much of moc reflection replaces. I wrote 48 rows, one per construct, each with a verdict and a test. +- 32 rows are "same". In 27 of them the meta-object equals a real moc's, and the behaviour matches. The other 5 have no twin. 4 rows are partial, 10 are unsupported, 1 needs a build step and 1 is not needed. - A QObject class, a derived class, a widget class and a gadget need no macro. The base class names the class for you. - Every open row has a reason. The largest: namespaces, `BINDABLE`, invokable constructors, plugin metadata and the `qmltyperegistrar` input. - The container from the spec series is one use case. A class template with signals is a row moc cannot have. @@ -28,15 +28,15 @@ import PostLink from '../../components/PostLink.astro'; A row names a moc construct, its spelling in moc and in reflect-moc, a verdict and a test. A script run by ctest fails on a blank cell, an unknown verdict or a missing test file. It also fails on a "same" row without a test. -In 24 of the 29 "same" rows there is a twin. One executable holds the class written for real moc in one header and for reflect-moc in another. The test compares the two meta-objects row for row: names, signatures, parameter names, access, flags, revisions, properties, enums and class info. Then it runs both. It calls methods by name, round-trips properties, connects signals and casts with `qobject_cast`. +In 27 of the 32 "same" rows there is a twin. One executable holds the class written for real moc in one header and for reflect-moc in another. The test compares the two meta-objects row for row: names, signatures, parameter names, access, flags, revisions, properties, enums and class info. Then it runs both. It calls methods by name, round-trips properties, connects signals and casts with `qobject_cast`. The other 5 are class templates, the class-name override, `qobject_cast` and two compile-time errors. I broke a twin on purpose once, by adding a property to the moc side only. The comparison failed. Without that check a comparison that always passes would look the same as one that works. | verdict | rows | meaning | |---|---|---| -| same | 29 | 24 equal real moc's meta-object and behaviour; 5 are tested without a twin | -| partial | 5 | works, with a difference the note names | -| unsupported | 11 | does not build, or is ignored with a message | +| same | 32 | 27 equal real moc's meta-object and behaviour; 5 are tested without a twin | +| partial | 4 | works, with a difference the note names | +| unsupported | 10 | does not build, or is ignored with a message | | impossible | 1 | needs a build step that reads moc's JSON | | not needed | 1 | there is no generated file to include | @@ -99,6 +99,8 @@ A class template needed one more step. The default must depend on a template par | `QPrivateSignal` | the tag as the last parameter | `parity_private_signal` | | `Q_ENUM`, `Q_FLAG` | `[[=rqt::enum_]]`, `[[=rqt::flag]]` | `parity_enum_from_type` | | overloaded signals, slots, invokables | one annotation per function | `parity_overloads_function_form` | +| several signatures in one signal member | `rqt::signal` | `parity_overloads_multi_member` | +| `WRITE` and `RESET` with overloads | the same rules as moc, by overload resolution | `parity_overloaded_property` | A gadget has no `QObject`, so Qt hands its address over as a pointer to a `QObject`. Its property code runs in the static meta-call, as moc's gadgets do. Reading and writing properties on a gadget, invoking its methods and storing it in a `QVariant` work with stock Qt. @@ -121,7 +123,7 @@ The regenerated spec runs on it. Its author's two corrections are fixed in both | plugin | `Q_PLUGIN_METADATA` | the JSON must be read at compile time and turned into CBOR by constexpr code | | QML | `QML_ELEMENT` and its family | registered by a call, not by the class: partial | | JSON | the input of `qmltyperegistrar` | a build step. A program built from the same classes could print it | -| overloads | one signal member with several signatures; an overloaded setter | two data members cannot share a name; a setter binds to the first overload | +| partial | default-argument clones of a non-public function; a signal or slot outside its section | the clones exist for public functions only; the compat header does not map the keywords | | enums | `QMetaEnum::fromType` in a macro-free class | needs two friend functions that a base class cannot declare for a derived class | The last row I checked by compiling a small file: the static assertion in Qt fails. The meta-object lists the enum, and a test covers that. There is no test yet for the failing `fromType` call. @@ -131,8 +133,8 @@ The last row I checked by compiling a small file: the static assertion in Qt fai - Only GCC 16.2 builds this, because only it has reflection here. Binding A of the spec also builds with MSVC and Clang, but that code uses moc. - Qt 6.10.3 only. `lupdate` scans source text and was not tried against these classes. - AI agents wrote most of the tests and the twins, under my direction. I reviewed the matrix and every verdict, not every line. -- 29 of 47 counts rows, and the rows are not equal in weight. A property row weighs more than a class-info row. +- 32 of 48 counts rows, and the rows are not equal in weight. A property row weighs more than a class-info row. ## Where to read it -The matrix is [`docs/moc-parity.md`](https://github.com/wrocpp/reflect-moc/blob/b2534166aa858f1b5acde22b7c1cc087d27ec4e3/docs/moc-parity.md), and the tests are in `tests/qt/parity` beside it. The macro audit, a table of each macro and its replacement, is at the end of the matrix. +The matrix is [`docs/moc-parity.md`](https://github.com/wrocpp/reflect-moc/blob/16c92da841d9ceb91c7581e209460e0ba2e59612/docs/moc-parity.md), and the tests are in `tests/qt/parity` beside it. The macro audit, a table of each macro and its replacement, is at the end of the matrix.