For C++: When you expose things with only macros and templates, without code generation, you end up having to repeat the name of each thing at least twice, because of how C++ compilation works. And you’ll have to remember to keep them in sync! (If C++ had static reflection, or even dynamic reflection through type_info, this wouldn’t be a problem, but no such luck …)
For most other languages: C#, Python, even Java support reflection, and most engines on top of those languages use that mechanism instead. Typically, you add decorators on top of the getters/setters/properties to tell the editor what to do and how to deal with it. Reflection often has performance implications, though. Compare how Unity games often use function names as messages and use reflection to discover them, which ends up costing a lot of performance.
If you need code generation, you need a custom build step of some sort, because C++ doesn’t have any support for code generation on its own. (As opposed to something like go:generate
in go, for example.)
Although the idea of a build being “custom” only really comes from IDE based environments like Visual Studio and XCode, most other environments use some kind of makefile approach (cmake / ninja / bazel / make / jam / whatever) and thus everything is “customer” – which means nothing is “custom,” that’s just how it’s done!