LINUX.ORG.RU

История изменений

Исправление ckotinko, (текущая версия) :

я тебя даже пожалел и написал тебе как можно сделать

много таких:
template<T1,T2...>
bool call(QObject * obj, char * method, const T1& t1, const T2& t2...) {
    //N = number of arguments
    QMetaMethod m = obj->metaObject()->methodIndex(method);
    if (!m.isValid() || m.argumentCount() != N) {
        //shit!
        return false;
    }
    int types[N] = {
        qMetaTypeId<T1>(),
        qMetaTypeId<T2>(),
        ...
    };
    const void ** args[N] = {
        &t1,
        &t2,
        ...
    };
    return do_really_call(obj, m, N, types, data);
}
static void do_clean_up(const QByteArray& data, int n) {
     Q_ASSERT(data.size() >= n * (sizeof(void*)*3);
     void ** hptr = (void**)data.data();
     for(int i = 0; i < n; ++i) {
         int t = PTR_TO_INT(hptr[2]);
         QMetaType::destruct(t, hptr[1]);
         hptr+=3;
     }
}
static bool do_really_call(QObject * obj, const QMetaMethod& m, int n, int ** const types, const void ** data) 
{
     int hdr_size = round_up_to_16(sizeof(void*)*3*n);
     int data_size = hdr_size;
     int offsets[n];//больше 10 аргументов все равно не поддерживают
     int dtypes[n];
     const char * names[n];
     for(int i = 0; i < n; ++i) {
         int pt = m.parameterType(i);
         if (pt != types[i]) {
            if (!QMetaType::hasRegisteredConvertedFunction(types[i], pt)) {
              return false;
            }
         }
         offsets[i] = data_size;
         dtypes[i] = pt;
         names[i] = QMetaType::typeName(pt);
         data_size += align_up_to_16(QMetaType::sizeOf(pt));
     }
     
     QByteArray data;
     data.resize(data_size);
     void ** hptr = (void**)data.data();
     void *  wptr = (void*)(data.data()+hdr_size);

     int J = 0;
     bool ok = true;
     for(J = 0; J < n; ++J) {
         *hptr = names[J];
         ++hptr;
         *hptr = wptr+offsets[J];
         ++hptr;
         *hptr = INT_TO_PTR(dtypes[J]);
         ++hptr;
         if (types[J] == dtypes[J]) 
            QMetaType::construct(types[J], wptr+offsets[J], data[J]);
         else
            ok = QMetaType::convert(data[J], types[J], wptr+offsets[J], dtypes[J]);
         if (!ok) break;
     }

     if (!ok) {
         do_clean_up(data, J);
         return false;
     }
     m.invoke(obj, Qt::QueuedConnection, "really_really_call", m.index(), n, data);
     return true;
}

//Q_INVOKABLE
void MyObject::really_really_call(int mi, int n, const QByteArray& args) {
   QMetaMethod m = metaObject()->method(mi);
   void ** hptr = (void**)args.data();
   //check for errors
   switch(n) {
      ...
   case 4:
      m.invoke(this, Qt::DirectConnection, 
               QGenericArgument(hptr[0*3], hptr[0*3+1]),
               QGenericArgument(hptr[1*3], hptr[1*3+1]),
               QGenericArgument(hptr[2*3], hptr[2*3+1]),
               QGenericArgument(hptr[3*3], hptr[3*3+1]));
      break;
   }
   do_clean_up(n, args);
}
это самый универсальный способ, который правда ничего не знает о типах, кроме того, что ты скажешь Qt

Исправление ckotinko, :

я тебя даже пожалел и написал тебе как можно сделать

много таких:
template<T1,T2...>
bool call(QObject * obj, char * method, const T1& t1, const T2& t2...) {
    //N = number of arguments
    QMetaMethod m = obj->metaObject()->methodIndex(method);
    if (!m.isValid() || m.argumentCount() != N) {
        //shit!
        return false;
    }
    int types[N] = {
        qMetaTypeId<T1>(),
        qMetaTypeId<T2>(),
        ...
    };
    const void ** args[N] = {
        &t1,
        &t2,
        ...
    };
    return do_really_call(obj, m, N, types, data);
}
static void do_clean_up(const QByteArray& data, int n) {
     Q_ASSERT(data.size() >= n * (sizeof(void*)*3);
     void ** hptr = (void**)data.data();
     for(int i = 0; i < n; ++i) {
         int t = PTR_TO_INT(hptr[2]);
         QMetaType::destruct(t, hptr[1]);
         hptr+=3;
     }
}
static bool do_really_call(QObject * obj, const QMetaMethod& m, int n, int ** const types, const void ** data) 
{
     int hdr_size = round_up_to_16(sizeof(void*)*3*n);
     int data_size = hdr_size;
     int offsets[n];//больше 10 аргументов все равно не поддерживают
     int dtypes[n];
     const char * names[n];
     for(int i = 0; i < n; ++i) {
         int pt = m.parameterType(i);
         if (pt != types[i]) {
            if (!QMetaType::hasRegisteredConvertedFunction(types[i], pt)) {
              return false;
            }
         }
         offsets[i] = data_size;
         dtypes[i] = pt;
         names[i] = QMetaType::typeName(pt);
         data_size += align_up_to_16(QMetaType::sizeOf(pt));
     }
     
     QByteArray data;
     data.resize(data_size);
     void ** hptr = (void**)data.data();
     void *  wptr = (void*)(data.data()+hdr_size);

     int J = 0;
     bool ok = true;
     for(J = 0; J < n; ++J) {
         *hptr = names[J];
         ++hptr;
         *hptr = wptr+offsets[J];
         ++hptr;
         *hptr = INT_TO_PTR(dtypes[J]);
         ++hptr;
         if (types[J] == dtypes[J]) 
            QMetaType::construct(types[J], wptr+offsets[J], data[J]);
         else
            ok = QMetaType::convert(data[J], types[J], wptr+offsets[J], dtypes[J]);
         if (!ok) break;
     }

     if (!ok) {
         do_clean_up(data, J);
         return false;
     }
     m.invoke(obj, Qt::QueuedConnection, "really_really_call", m.index(), n, data);
     return true;
}

//Q_INVOKABLE
void MyObject::really_really_call(int mi, int n, const QByteArray& args) {
   QMetaMethod m = metaObject()->method(mi);
   void ** hptr = (void**)args.data();
   //check for errors
   switch(n) {
      ...
   case 4:
      m.invoke(this, Qt::DirectConnection, 
               QGenericArgument(hptr[0*3], hptr[0*3+2]),
               QGenericArgument(hptr[1*3], hptr[1*3+2]),
               QGenericArgument(hptr[2*3], hptr[2*3+2]),
               QGenericArgument(hptr[3*3], hptr[3*3+2]));
      break;
   }
   do_clean_up(n, args);
}
это самый универсальный способ, который правда ничего не знает о типах, кроме того, что ты скажешь Qt

Исходная версия ckotinko, :

я тебя даже пожалел и написал тебе как можно сделать

много таких:
template<T1,T2...>
bool call(QObject * obj, char * method, const T1& t1, const T2& t2...) {
    //N = number of arguments
    QMetaMethod m = obj->metaObject()->methodIndex(method);
    if (!m.isValid() || m.argumentCount() != N) {
        //shit!
        return false;
    }
    int types[N] = {
        qMetaTypeId<T1>(),
        qMetaTypeId<T2>(),
        ...
    };
    const void ** args[N] = {
        &t1,
        &t2,
        ...
    };
    return do_really_call(obj, m, N, types, data);
}
static void do_clean_up(const QByteArray& data, int n) {
     Q_ASSERT(data.size() >= n * (sizeof(void*)*3);
     void ** hptr = (void**)data.data();
     for(int i = 0; i < n; ++i) {
         int t = PTR_TO_INT(hptr[2]);
         QMetaType::destruct(t, hptr[1]);
         hptr+=3;
     }
}
static bool do_really_call(QObject * obj, const QMetaMethod& m, int n, int ** const types, const void ** data) 
{
     int hdr_size = round_up_to_16(sizeof(void*)*3*n);
     int data_size = hdr_size;
     int offsets[n];//больше 10 аргументов все равно не поддерживают
     int dtypes[n];
     const char * names[n];
     for(int i = 0; i < n; ++i) {
         int pt = m.parameterType(i);
         if (pt != types[i]) {
            if (!QMetaType::hasRegisteredConvertedFunction(types[i], pt)) {
              return false;
            }
         }
         offsets[i] = data_size;
         dtypes[i] = pt;
         names[i] = QMetaType::typeName(pt);
         data_size += align_up_to_16(QMetaType::sizeOf(pt));
     }
     
     QByteArray data;
     data.resize(data_size);
     void ** hptr = (void**)data.data();
     void *  wptr = (void*)(data.data()+hdr_size);

     int J = 0;
     bool ok = true;
     for(J = 0; J < n; ++J) {
         *hptr = names[J];
         ++hptr;
         *hptr = wptr;
         ++hptr;
         *hptr = INT_TO_PTR(dtypes[J]);
         ++hptr;
         if (types[J] == dtypes[J]) 
            QMetaType::construct(types[J], wptr, data[J]);
         else
            ok = QMetaType::convert(data[J], types[J], wptr, dtypes[J]);
         if (!ok) break;
     }

     if (!ok) {
         do_clean_up(data, J);
         return false;
     }
     m.invoke(obj, Qt::QueuedConnection, "really_really_call", m.index(), n, data);
     return true;
}

//Q_INVOKABLE
void MyObject::really_really_call(int mi, int n, const QByteArray& args) {
   QMetaMethod m = metaObject()->method(mi);
   void ** hptr = (void**)args.data();
   //check for errors
   switch(n) {
      ...
   case 4:
      m.invoke(this, Qt::DirectConnection, 
               QGenericArgument(hptr[0*3], hptr[0*3+2]),
               QGenericArgument(hptr[1*3], hptr[1*3+2]),
               QGenericArgument(hptr[2*3], hptr[2*3+2]),
               QGenericArgument(hptr[3*3], hptr[3*3+2]));
      break;
   }
   do_clean_up(n, args);
}
это самый универсальный способ, который правда ничего не знает о типах, кроме того, что ты скажешь Qt