1/****************************************************************************
2 * Copyright (C) 2014 Woboq GmbH
3 * Olivier Goffart <contact at woboq.com>
4 * http://woboq.com/blog/reflection-in-cpp-and-qt-moc.html
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 *
19 ****************************************************************************
20 *
21 * This is a tentative to build the QMetaObject and all the moc generated
22 * code at compile time using a normal C++ compiler
23 *
24 * This code is based on ideas from N3951, and requires C++14. It has been
25 * tested with clang 3.4 only
26 *
27 * Instructions to compile:
28 * clang++ -std=c++1y ./metaobjectbuilder.cc -I/usr/include/qt -fPIC -lQt5Core -O2
29 *
30 * This is just a prototype
31 *
32 * More information:
33 * http://woboq.com/blog/reflection-in-cpp-and-qt-moc.html
34 *
35 * Since we do not have typename<>... and typedef<>... those are manually expanded.
36 * Also, there is a lot of other traits missing, and for this reason, every method
37 * is considered to be a signal.
38 */
39
40char *gets(char *s); // Fix compilation error in the headers with c++1y with clang
41#include <QtCore/QtCore>
42#include <tuple>
43#include <utility>
44
45
46// This would go in the qobjectdefs.h header with the other defines
47template <typename Type, typename... T> struct QProperty : std::tuple<T...> {
48 using std::tuple<T...>::tuple;
49 using PropertyType = Type;
50};
51template <typename Type, typename... T> constexpr auto qt_makeProperty(T&& ...t)
52{ return QProperty<Type, typename std::decay<T>::type...>{ std::forward<T>(t)... }; }
53
54#define Q_PROPERTY2(TYPE, NAME, ...) static constexpr auto qt_property_##NAME = \
55 qt_makeProperty<TYPE>(__VA_ARGS__);
56
57
58/*-----------------------------------------------------------------------------------------------*/
59/* Implements the extensions in terms of traits to be specialized manually */
60/*-----------------------------------------------------------------------------------------------*/
61
62
63/**
64 * the implementation of typename...
65 *
66 * typename_<T>::staticStringList();
67 * would be the same as
68 * makeStaticStringList(typename<T>...)
69 *
70 */
71template <typename T> struct typename_;
72// { static constexpr auto staticStringList() { return makeStaticStringList(typename<T>...); } };
73
74/**
75 * the implemtnation of typedef...
76 *
77 * typedef_<T>::tuple()
78 * vould be the same as
79 * std::make_tuple(typedef<T>...)
80 */
81template <typename T> struct typedef_;
82// { static constexpr auto tuple() { return make_tuple(typedef<T>...); } };
83
84
85/*-----------------------------------------------------------------------------------------------*/
86/* Helpers to play with tuple or strings at compile time */
87/*-----------------------------------------------------------------------------------------------*/
88
89
90/**
91 * define index_sequence and make_index_sequence since I don't have C++14 headers
92 */
93template<int...I> struct index_sequence {
94 /** Added an operator+ to concatenate two sequences */
95 template<int... J> constexpr index_sequence<I...,J...> operator+(index_sequence<J...>) const { return {}; }
96};
97template<int I> struct make_integer_sequence_helper {
98 template<int... Is> static index_sequence<Is..., I-1> func(index_sequence<Is...>);
99 using result = decltype(func(typename make_integer_sequence_helper<I-1>::result()));
100};
101template<> struct make_integer_sequence_helper<0> { using result = index_sequence<>; };
102template<int I> using make_index_sequence = typename make_integer_sequence_helper<I>::result;
103
104
105/**
106 * tuple_tail() Returns a tuple with the first element removed
107 */
108template<typename T, int...I> constexpr auto tuple_tail_helper(const T&t , index_sequence<I...>) {
109 return std::make_tuple(std::get<I+1>(t)...);
110}
111template<typename T> constexpr auto tuple_tail(const T& tuple) {
112 return tuple_tail_helper(tuple, make_index_sequence<std::tuple_size<T>::value-1>());
113}
114
115
116/** zip():
117 * make tuple<pair<A1, B1>, pair<A2, B2>, ...> from two tuples tuple<A1, A2, ...> and tuple<B1, B2, ...>
118 */
119template<typename A, typename B, int... I>
120constexpr auto zip_helper(A a, B b, index_sequence<I...>) {
121 return std::make_tuple( std::make_pair(std::get<I>(a), std::get<I>(b))... );
122}
123template<typename A, typename B>
124constexpr auto zip(A a, B b) {
125 static_assert(std::tuple_size<A>::value == std::tuple_size<B>::value,
126 "arguments must be tuples of the same sizes");
127 return zip_helper(a, b, make_index_sequence<std::tuple_size<A>::value>());
128}
129
130
131
132/*
133 * Helpers to play with static strings
134 */
135
136/** A compile time character array of size N */
137template<int N> using StaticStringArray = const char [N];
138
139/** Represents a string of size N (N includes the 0 at the end) */
140template<int N> struct StaticString {
141 StaticStringArray<N> data;
142 template <int... I>
143 constexpr StaticString(StaticStringArray<N> &d, index_sequence<I...>) : data{ (d[I])... } { }
144 constexpr StaticString(StaticStringArray<N> &d) : StaticString(d, make_index_sequence<N>()) {}
145 static constexpr int size = N;
146 constexpr char operator[](int p) const { return data[p]; }
147};
148
149/* A tuple containing many StaticString with possibly different sizes */
150template<int ...Sizes> using StaticStringList = std::tuple<StaticString<Sizes>...>;
151
152/* Creates a StaticStringList from a list of string literal */
153template<int... N>
154constexpr StaticStringList<N...> makeStaticStringList(StaticStringArray<N> & ...args) {
155 return std::make_tuple(StaticString<N>(args)...);
156}
157
158/** concatenate() : returns a StaticString which is the concatenation of all the strings in a StaticStringList
159 * Note: keeps the \0 between the strings
160 */
161template<typename I1, typename I2> struct concatenate_helper;
162template<int... I1, int... I2> struct concatenate_helper<index_sequence<I1...>, index_sequence<I2...>> {
163 static constexpr int size = sizeof...(I1) + sizeof...(I2);
164 static constexpr auto concatenate(const StaticString<sizeof...(I1)> &s1, const StaticString<sizeof...(I2)> &s2) {
165 StaticStringArray<size> d = { s1[I1]... , s2[I2]... };
166 return StaticString<size>( d );
167 }
168};
169constexpr StaticString<1> concatenate(const StaticStringList<>) { return ""; }
170template<int H, int... T> constexpr auto concatenate(const StaticStringList<H, T...> &s) {
171 auto tail = concatenate(tuple_tail(s));
172 return concatenate_helper<make_index_sequence<H>, make_index_sequence<tail.size>>::concatenate(std::get<0>(s), tail);
173}
174
175/** Add a string in a StaticStringList */
176template<int L, int...N >
177constexpr auto addString(const StaticStringList<N...> &l, const StaticString<L> & s) {
178 return std::tuple_cat(l, std::make_tuple(s));
179}
180
181
182/*-----------------------------------------------------------------------------------------------*/
183/* The code that generates the QMetaObject */
184/*-----------------------------------------------------------------------------------------------*/
185namespace MetaObjectBuilder {
186
187 /** Holds information about a method */
188 template<typename F, int NameLength>
189 struct MetaMethodInfo {
190 enum { Signal, Slot } type;
191 enum { Public, Protected, Private } access;
192 F func;
193 StaticString<NameLength> name;
194 static constexpr int argCount = QtPrivate::FunctionPointer<F>::ArgumentCount;
195 using ReturnType = typename QtPrivate::FunctionPointer<F>::ReturnType;
196
197 template<typename T>
198 void metacall(T *_o, QMetaObject::Call _c, void **_a) const {
199 if (_c == QMetaObject::InvokeMetaMethod) {
200 using P = QtPrivate::FunctionPointer<F>;
201 P::template call<typename P::Arguments, ReturnType>(func, _o, _a);
202 }
203 }
204 };
205
206 /** Holds information about a property */
207 template<typename Type, int NameLength, typename Getter, typename Setter, typename Member, typename Notify>
208 struct MetaPropertyInfo {
209 using PropertyType = Type;
210 StaticString<NameLength> name;
211 Getter getter;
212 Setter setter;
213 Member member;
214 Notify notify;
215 uint flags = 0;
216
217 template <typename S> constexpr auto setGetter(const S&s) const
218 { return MetaPropertyInfo<Type, NameLength, S, Getter, Member, Notify>{name, s, setter, member, notify, flags}; }
219 template <typename S> constexpr auto setSetter(const S&s) const
220 { return MetaPropertyInfo<Type, NameLength, Getter, S, Member, Notify>{name, getter, s, member, notify, flags}; }
221 template <typename S> constexpr auto setMember(const S&s) const
222 { return MetaPropertyInfo<Type, NameLength, Getter, Setter, S, Notify>{name, getter, setter, s, notify, flags}; }
223
224 template<typename T>
225 void metacall(T *_o, QMetaObject::Call _c, void **_a) const {
226 switch(+_c) {
227 case QMetaObject::ReadProperty:
228 if (getter) {
229 *reinterpret_cast<Type*>(_a[0]) = (_o->*getter)();
230 } else if (member) {
231 *reinterpret_cast<Type*>(_a[0]) = _o->*member;
232 }
233 break;
234 case QMetaObject::WriteProperty:
235 if (setter) {
236 (_o->*setter)(*reinterpret_cast<Type*>(_a[0]));
237 } else if (member) {
238 _o->*member = *reinterpret_cast<Type*>(_a[0]);
239 }
240 }
241 }
242 };
243
244 /** Just a dummy pointer to member function to be used when there is none */
245 template<typename T> struct DummyFunctPointer { operator bool() const { return false; } };
246 template<typename T, typename O> T &operator->*(O*, DummyFunctPointer<T>) { return *static_cast<T*>(nullptr); }
247
248 /** Parse a property and fill a MetaPropertyInfo */
249 template <typename PropInfo> constexpr auto parseProperty(const PropInfo &p, const std::tuple<> &) { return p; }
250 template <typename PropInfo, typename Obj, typename Arg, typename Ret, typename... Tail>
251 constexpr auto parseProperty(const PropInfo &p, const std::tuple<Ret (Obj::*)(Arg), Tail...> &t) {
252 return parseProperty(p.setSetter(std::get<0>(t)) ,tuple_tail(t));
253 }
254 template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
255 constexpr auto parseProperty(const PropInfo &p, const std::tuple<Ret (Obj::*)(), Tail...> &t) {
256 return parseProperty(p.setGetter(std::get<0>(t)) ,tuple_tail(t));
257 }
258 template <typename PropInfo, typename Obj, typename Ret, typename... Tail>
259 constexpr auto parseProperty(const PropInfo &p, const std::tuple<Ret (Obj::*), Tail...> &t) {
260 return parseProperty(p.setMember(std::get<0>(t)) ,tuple_tail(t));
261 }
262
263 template<typename P, int... I>
264 constexpr auto makePropertyInfo(const StaticString<sizeof...(I)+12> &n, const P &p, index_sequence<I...>) {
265 constexpr int nSize = sizeof...(I);
266 StaticStringArray<nSize> d = { n[I+12]... };
267 using Type = typename P::PropertyType;
268 using Dummy = DummyFunctPointer<Type>;
269 MetaPropertyInfo<Type, sizeof...(I), Dummy, Dummy, Dummy, Dummy> meta { d };
270 return parseProperty(meta, p);
271 }
272
273
274 /** Holds information about a class, includeing all the properties and methods */
275 template<int NameLength, typename Methods, typename Properties>
276 struct ClassInfo {
277 StaticString<NameLength> name;
278 Methods methods;
279 Properties properties;
280
281 template<typename M>
282 constexpr auto addMethod(const M&m) const {
283 auto newM = std::tuple_cat(methods, std::make_tuple(m));
284 return ClassInfo<NameLength, decltype(newM), Properties>{ name, newM, properties };
285 }
286
287 template<typename P>
288 constexpr auto addProperty(const P&p) const {
289 auto newP = std::tuple_cat(properties, std::make_tuple(p));
290 return ClassInfo<NameLength, Methods, decltype(newP)>{ name, methods, newP };
291 }
292
293 static constexpr int methodCount = std::tuple_size<Methods>::value;
294 static constexpr int propertyCount = std::tuple_size<Properties>::value;
295 };
296 /** Construct a ClassInfo with just the name */
297 template<typename T, int N>
298 constexpr auto makeClassInfo(const StaticString<N> &name)
299 -> ClassInfo<N, std::tuple<>, std::tuple<>>
300 { return { name, {}, {} }; }
301
302
303 /**
304 * parseMember(ClassInfo, member, name) :
305 * member and name are coming from the typedef... and typename... traits
306 * if member is a signal, slot, or property, add it to the ClassInfo
307 */
308 // Generic: don't do nothing.
309 template<typename ClassInfo, typename T, int N>
310 constexpr auto parseMember(const ClassInfo &ci, const T&, const StaticString<N> &) { return ci; }
311 // A method. (I consider everything as a signal for now)
312 template<typename ClassInfo, int N, class O, typename Ret, typename... A>
313 constexpr auto parseMember(const ClassInfo &ci, Ret (O::*func)(A...) , const StaticString<N> &name) {
314 using MI = MetaMethodInfo<decltype(func), N>;
315 return ci.addMethod(MI{ MI::Signal, MI::Public, func, name});
316 }
317 // A property
318 template<typename ClassInfo, int N, typename T, typename... P>
319 constexpr auto parseMember(const ClassInfo &ci, QProperty<T, P...> p, const StaticString<N> &name) {
320 return ci.addProperty(makePropertyInfo(name, p, make_index_sequence<N-12>()));
321 }
322
323 /**
324 * MemberParser<std::tuple<std::pair<member, name>...>>::parse(...)
325 * apply parseMember to all members
326 */
327 template<typename> struct MembersParser {
328 template<typename R>
329 static constexpr auto parse(const R & r, const std::tuple<> &) { return r; }
330 };
331 template<typename Head, typename ...Tail>
332 struct MembersParser<std::tuple<Head , Tail...>> {
333 private:
334 template<typename R, int... I>
335 static constexpr auto parseNext(const R&r, const std::tuple<Head , Tail...> &t) {
336 return MembersParser<std::tuple<Tail...>>::parse(r, tuple_tail(t));
337 }
338 public:
339 template<typename R>
340 static constexpr auto parse(const R&r, const std::tuple<Head , Tail...> &t) {
341 return parseNext(parseMember(r, std::get<0>(t).first, std::get<0>(t).second), t);
342 }
343 };
344
345
346 /**
347 * generate...
348 * Create the metaobject's integer data array
349 * (as a index_sequence)
350 * returns std::pair<StaticStringList, index_sequence>: the modified strings and the array of strings
351 */
352 template<int, typename Strings>
353 constexpr auto generateMethods(const Strings &s, const std::tuple<>&) {
354 return std::make_pair(s, index_sequence<>());
355 }
356 template<int ParamIndex, typename Strings, typename Method, typename... Tail>
357 constexpr auto generateMethods(const Strings &s, const std::tuple<Method, Tail...> &t) {
358
359 auto method = std::get<0>(t);
360 auto s2 = addString(s, method.name);
361
362 using thisMethod = index_sequence<std::tuple_size<Strings>::value, //name
363 Method::argCount,
364 ParamIndex, //parametters
365 1, //tag, always \0
366 0x0a /* hardcoded flags: Public */
367 >;
368
369 auto next = generateMethods<ParamIndex + 1 + Method::argCount * 2>(s2, tuple_tail(t));
370 return std::make_pair(next.first, thisMethod() + next.second);
371 }
372
373 template<typename Strings>
374 constexpr auto generateProperties(const Strings &s, const std::tuple<>&) {
375 return std::make_pair(s, index_sequence<>());
376 }
377 template<typename Strings, typename Prop, typename... Tail>
378 constexpr auto generateProperties(const Strings &s, const std::tuple<Prop, Tail...> &t) {
379
380 auto prop = std::get<0>(t);
381 auto s2 = addString(s, prop.name);
382
383 using thisProp = index_sequence<std::tuple_size<Strings>::value, //name
384 qMetaTypeId<typename Prop::PropertyType>(),
385 0x03 /* hardcoded flags: Public */
386 >;
387
388 auto next = generateProperties(s2, tuple_tail(t));
389 return std::make_pair(next.first, thisProp() + next.second);
390
391 }
392
393
394 //Helper class for generateSingleMethodParameter: generate the parametter array
395 template<typename ...Args> struct HandleArgsHelper { using Result = index_sequence<>; };
396 template<typename A, typename... Args>
397 struct HandleArgsHelper<A, Args...> {
398 using Result = decltype(index_sequence<qMetaTypeId<A>(), 1>() + typename HandleArgsHelper<Args...>::Result());
399 };
400
401 template<typename Strings, typename Obj, typename Ret, typename... Args>
402 constexpr auto generateSingleMethodParameter(const Strings &ss, Ret (Obj::*)(Args...) ) {
403 constexpr int retTyp = qMetaTypeId<Ret>();
404 return std::make_pair(ss, index_sequence<retTyp>() + typename HandleArgsHelper<Args...>::Result());
405 }
406
407 template<typename Strings>
408 constexpr auto generateMethodsParameters(const Strings &s, const std::tuple<>&) {
409 return std::make_pair(s, index_sequence<>());
410 }
411 template<typename Strings, typename Method, typename... Tail>
412 constexpr auto generateMethodsParameters(const Strings &s, const std::tuple<Method, Tail...> &t) {
413 auto method = std::get<0>(t);
414 auto thisMethod = generateSingleMethodParameter(s, method.func);
415 auto next = generateMethodsParameters(thisMethod.first, tuple_tail(t));
416 return std::make_pair(next.first, thisMethod.second + next.second);
417 }
418
419 // generate the integer array and the lists of string
420 template<typename CI>
421 constexpr auto generateDataArray(const CI &classInfo) {
422 constexpr int methodOffset = 14;
423 constexpr int propertyOffset = methodOffset + CI::methodCount * 5;
424 constexpr int paramIndex = propertyOffset + CI::propertyCount * 3 ;
425 using header = index_sequence<
426 7, // revision
427 0, // classname
428 0, 0, // classinfo
429 CI::methodCount, methodOffset, // methods
430 CI::propertyCount, propertyOffset, // properties
431 0, 0, // enums/sets
432 0, 0, // constructors
433 0, // flags
434 CI::methodCount // signalCount /* Yes, everything is considered signal for now */
435 >;
436 auto stringData = std::make_tuple(classInfo.name, StaticString<1>(""));
437 auto methods = generateMethods<paramIndex>(stringData , classInfo.methods);
438 auto properties = generateProperties(methods.first , classInfo.properties);
439 auto parametters = generateMethodsParameters(properties.first, classInfo.methods);
440 return std::make_pair(parametters.first, header() + methods.second + properties.second + parametters.second);
441 }
442
443
444
445 /**
446 * Entry class for the generation of the QMetaObject
447 */
448
449 template<typename T> struct MetaObjectCreatorHelper {
450 private:
451 static constexpr auto names = typename_<T>::staticStringList();
452 static constexpr auto values = typedef_<T>::tuple();
453 static constexpr auto zipped = zip(values, names);
454
455 public:
456
457 using Base = typename std::remove_reference<decltype(*std::get<1>(values))>::type;
458
459 static constexpr auto classInfo = MembersParser<typename std::remove_const<decltype(zipped)>::type>::parse(
460 makeClassInfo<T>(std::get<0>(zipped).second), zipped);
461 static constexpr auto data = generateDataArray(classInfo);
462 static constexpr auto string_data = data.first;
463 static constexpr auto int_data = data.second;
464 };
465
466
467 /**
468 * Holder for the string data. Just like in the moc generated code.
469 */
470 template<int N, int L> struct qt_meta_stringdata_t {
471 QByteArrayData data[N];
472 char stringdata[L];
473 };
474
475 /** Builds the string data
476 * \param S: a index_sequence that goes from 0 to the fill size of the strings
477 * \param I: a index_sequence that goes from 0 to the number of string
478 * \param O: a index_sequence of the offsets
479 * \param N: a index_sequence of the size of each strings
480 * \param T: the MetaObjectCreatorHelper
481 */
482 template<typename S, typename I, typename O, typename N, typename T> struct BuildStringDataHelper;
483 template<int... S, int... I, int... O, int...N, typename T>
484 struct BuildStringDataHelper<index_sequence<S...>, index_sequence<I...>, index_sequence<O...>, index_sequence<N...>, T> {
485 using meta_stringdata_t = const qt_meta_stringdata_t<sizeof...(I), sizeof...(S)>;
486 static meta_stringdata_t qt_meta_stringdata;
487 };
488 template<int... S, int... I, int... O, int...N, typename T>
489 const qt_meta_stringdata_t<sizeof...(I), sizeof...(S)>
490 BuildStringDataHelper<index_sequence<S...>, index_sequence<I...>, index_sequence<O...>, index_sequence<N...>, T>::qt_meta_stringdata = {
491 {Q_STATIC_BYTE_ARRAY_DATA_HEADER_INITIALIZER_WITH_OFFSET(N-1,
492 qptrdiff(offsetof(meta_stringdata_t, stringdata) + O - I * sizeof(QByteArrayData)) )...},
493 { concatenate(T::string_data)[S]... }
494 };
495
496
497
498 /* Compute the sum of many integers */
499 constexpr int sums() { return 0; }
500 template<typename... Args>
501 constexpr int sums(int i, Args... args) { return i + sums(args...); }
502
503 /**
504 * Given N a list of string sizes, compute the list offsets to each of the strings.
505 */
506 template<int... N> struct ComputeOffsets;
507 template<> struct ComputeOffsets<> {
508 using Result = index_sequence<>;
509 };
510 template<int H, int... T> struct ComputeOffsets<H, T...> {
511 template<int ... I> static index_sequence<0, (I+H)...> func(index_sequence<I...>);
512 using Result = decltype(func(typename ComputeOffsets<T...>::Result()));
513 };
514
515
516 /**
517 * returns the string data suitable for the QMetaObject from a list of string
518 * T is MetaObjectCreatorHelper<ObjectType>
519 */
520 template<typename T, int... N>
521 constexpr const QByteArrayData *build_string_data(StaticStringList<N...>) {
522 return BuildStringDataHelper<make_index_sequence<sums(N...)>,
523 make_index_sequence<sizeof...(N)>,
524 typename ComputeOffsets<N...>::Result,
525 index_sequence<N...>,
526 T>
527 ::qt_meta_stringdata.data;
528 }
529
530 /**
531 * returns a pointer to an array of string built at compile time.
532 */
533 template<typename I> struct build_int_data;
534 template<int... I> struct build_int_data<index_sequence<I...>> {
535 static const uint data[sizeof...(I)];
536 };
537 template<int... I> const uint build_int_data<index_sequence<I...>>::data[sizeof...(I)] = { I... };
538
539
540 /**
541 * calls metacall on each element of the tuple
542 */
543 template<typename T> void metacall(T *, QMetaObject::Call, int , void** , const std::tuple<> &) {}
544 template<typename T, typename Ms> void metacall(T *_o, QMetaObject::Call _c, int _id, void** _a, const Ms &ms) {
545 if (_id == 0) {
546 std::get<0>(ms).metacall(_o, _c, _a);
547 } else {
548 metacall(_o, _c, _id-1, _a, tuple_tail(ms));
549 }
550 }
551
552 /**
553 * Helper for QMetaObject::IndexOfMethod
554 */
555 void indexOfMethod (int *, void **, int, const std::tuple<> &) {}
556 template<typename Ms> void indexOfMethod (int *result, void **func, int _id, const Ms &ms) {
557 auto f = std::get<0>(ms).func;
558 if (f == *reinterpret_cast<decltype(f)*>(func)) {
559 *result = _id;
560 } else {
561 indexOfMethod(result, func, _id+1, tuple_tail(ms));
562 }
563 }
564
565}
566
567template<typename T>
568constexpr QMetaObject createMetaObject()
569{
570 using Creator = MetaObjectBuilder::MetaObjectCreatorHelper<T>;
571
572 auto string_data = MetaObjectBuilder::build_string_data<Creator>(Creator::string_data);
573 auto int_data = MetaObjectBuilder::build_int_data<typename std::remove_const<decltype(Creator::int_data)>::type>::data;
574
575
576 //return MetaObjectBuilder::makeStringList("MyObject", "setFoo", "getFoo", "setBar");
577 return { { &Creator::Base::staticMetaObject , string_data , int_data, T::qt_static_metacall } };
578}
579
580template<typename T> int qt_metacall_impl(T *_o, QMetaObject::Call _c, int _id, void** _a) {
581 using Creator = MetaObjectBuilder::MetaObjectCreatorHelper<T>;
582 _id = _o->Creator::Base::qt_metacall(_c, _id, _a);
583 if (_id < 0)
584 return _id;
585 if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {
586 constexpr int methodCount = Creator::classInfo.methodCount;
587 if (_id < methodCount)
588 T::qt_static_metacall(_o, _c, _id, _a);
589 _id -= methodCount;
590 } else if ((_c >= QMetaObject::ReadProperty && _c <= QMetaObject::QueryPropertyUser)
591 || _c == QMetaObject::RegisterPropertyMetaType) {
592 constexpr auto ps = Creator::classInfo.properties;
593 MetaObjectBuilder::metacall(_o, _c, _id, _a, ps);
594 }
595
596 return _id;
597}
598
599template<typename T> void qt_static_metacall_impl(QObject *_o, QMetaObject::Call _c, int _id, void** _a) {
600 constexpr auto ms = MetaObjectBuilder::MetaObjectCreatorHelper<T>::classInfo.methods;
601 if (_c == QMetaObject::InvokeMetaMethod || _c == QMetaObject::RegisterMethodArgumentMetaType) {
602 Q_ASSERT(T::staticMetaObject.cast(_o));
603 MetaObjectBuilder::metacall(static_cast<T*>(_o), _c, _id, _a, ms);
604 } else if (_c == QMetaObject::IndexOfMethod) {
605 MetaObjectBuilder::indexOfMethod(reinterpret_cast<int *>(_a[0]), reinterpret_cast<void **>(_a[1]), 0, ms);
606 }
607}
608
609template<typename Func, int Idx> struct SignalImplementation {};
610template<typename Ret, typename Obj, typename... Args, int Idx>
611struct SignalImplementation<Ret (Obj::*)(Args...), Idx>{
612 static Ret impl (Obj *this_,Args... args) {
613 Ret r{};
614 void * a[]= { &r, (&args)... };
615 QMetaObject::activate(this_, &Obj::staticMetaObject, Idx, a);
616 return r;
617 }
618};
619template<typename Obj, typename... Args, int Idx>
620struct SignalImplementation<void (Obj::*)(Args...), Idx>{
621 static void impl (Obj *this_,Args... args) {
622 void *a[]= { nullptr, (&args)... };
623 QMetaObject::activate(this_, &Obj::staticMetaObject, Idx, a);
624 }
625};
626
627
628/*-----------------------------------------------------------------------------------------------*/
629/* Example object and test */
630/*-----------------------------------------------------------------------------------------------*/
631
632class MyObject : public QObject {
633
634 using ThisType = MyObject;
635
636 Q_OBJECT
637 // Unfortunately we need the friends right now do that for now, but that could go in the Q_OBJECT macro
638 template<typename T> friend constexpr QMetaObject createMetaObject();
639 template<typename T> friend int qt_metacall_impl(T *, QMetaObject::Call, int, void**);
640
641public slots:
642 void setFoo(int value) { qDebug() << Q_FUNC_INFO << value; };
643 int getFoo() { return 0; };
644 void setBar() { }
645 QObject *getBar() { return this; }
646signals: // would expands to public [[qt::signals]]:
647 void fooChanged();
648 void barChanged(int);
649
650public:
651
652 Q_PROPERTY2(int, foo, &MyObject::getFoo, &MyObject::setFoo)
653
654};
655
656/**
657 * Reimplementation of the fake traits. All expanded by hands
658 */
659template<> struct typename_<MyObject> {
660 static constexpr auto staticStringList() {
661 return makeStaticStringList("MyObject", "QObject", "setFoo", "getFoo", "setBar", "fooChanged", "barChanged", "qt_property_foo");
662 }
663};
664template<> struct typedef_<MyObject> {
665 using T = MyObject;
666 static constexpr auto tuple() {
667 return std::make_tuple(static_cast<T*>(nullptr), static_cast<QObject*>(nullptr), &T::setFoo, &T::getFoo, &T::setBar, &T::fooChanged, &T::barChanged, T::qt_property_foo);
668 }
669};
670
671
672/**
673 * This could go in a macro:
674 * Q_OBJECT_IMPL(MyObject)
675 */
676
677const QMetaObject MyObject::staticMetaObject = createMetaObject<MyObject>();
678const QMetaObject *MyObject::metaObject() const { return &staticMetaObject; }
679
680void *MyObject::qt_metacast(const char *) { return nullptr; } // Yeah...
681int MyObject::qt_metacall(QMetaObject::Call _c, int _id, void** _a) {
682 return qt_metacall_impl<MyObject>(this, _c, _id, _a);
683}
684
685void MyObject::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void** _a) {
686 qt_static_metacall_impl<MyObject>(_o, _c, _id, _a);
687}
688
689
690
691/** Signal implementation: I don't know how it could be done */
692
693void MyObject::fooChanged() {
694 return SignalImplementation<decltype(&MyObject::fooChanged), 3>::impl(this);
695}
696
697void MyObject::barChanged(int i) {
698 return SignalImplementation<decltype(&MyObject::barChanged), 4>::impl(this, i);
699}
700
701
702
703/** Some tests */
704
705int main() {
706 MyObject obj;
707 qDebug() << obj.metaObject()->className();
708// qDebug() << obj.metaObject()->method(5).parameterCount();
709 QMetaObject::invokeMethod(&obj, "setFoo", Q_ARG(int, 111));
710
711// qDebug() << obj.metaObject()->indexOfMethod("barChanged(int)") - obj.metaObject()->methodOffset();
712 QObject::connect(&obj,SIGNAL(barChanged(int)), &obj, SIGNAL(setFoo(int))); // (setFoo is using SIGNAL because all method are signal in this prototype)
713 QObject::connect(&obj, &MyObject::barChanged, [](auto q){ qDebug() << Q_FUNC_INFO << q; });
714 obj.barChanged(222);
715
716 obj.setProperty("foo", 333);
717}
718
719