2

I have a variadic template class for keeping answers from own net class

enum class TaskType {readReg, writeReg, readRnd, writeRnd, readBlock, writeBlock, pause};

template<typename... Args> class Reply {
public:
    Reply(TaskType t, Args...params): t(t), tuple(std::make_tuple(params...)) {}
    Reply();
    TaskType t;
    auto getData() const {return std::get<4>(tuple);}   //simplified getter of safe function that deals with oversizing
private:
    std::tuple<Args ...> tuple;
};

I register template signatures to keep them in Qvariant

using ReadRegReply = Reply<TaskType, uint, uint, uint, uint, uint> ;
using WriteReply = Reply<TaskType, uint, uint, uint> ;
using ReadRndReply = Reply<TaskType, uint, uint, uint, QVector<uint>, QVector<uint>> ;
using ReadBlockReply = Reply<TaskType, uint, uint, uint, uint, QVector<uint>> ;

Q_DECLARE_METATYPE(QVector<uint>)
Q_DECLARE_METATYPE(ReadRegReply)
Q_DECLARE_METATYPE(WriteReply)
Q_DECLARE_METATYPE(ReadRndReply)
Q_DECLARE_METATYPE(ReadBlockReply)

Then I work with it like this:

class Task: public QObject{ 
public:
//c-tor and some functions, virtual functions etc
template <class TReply> bool applyReply(TReply reply){
    varReply = QVariant::fromValue(reply);
}
auto getData(){  //here I should return data from tuple inside reply.
   QVariant::Type t = varReply.type();
   auto l = varReply.value<t>();// t is not a constexp // t is not a reply type but enum QVariant::type, as I understand.
   return l.getData(); // l has no method getData
}
QVariant varReply;      //this is the qvariant that contains templated reply;
}

There is something i miss in QVariant. I thought that registered type should be stored somehow in Qvariant but it's not like that. The other problems: I can't use c++17; it will be used in many projects with different replies signatures. Is there some way to keep these types and add them in the future without total refactoring? I thought about some kind of manager class, but i might be overthinking

Greadimar
  • 81
  • 8
  • To register a type you have to use the qRegisterMetatype("ClassName"); – Moia Dec 04 '18 at 08:28
  • @Moia qRegisterMetatype is to make the type can be transmitted through signals, it is unnecessary if you want to use QVariant – eyllanesc Dec 04 '18 at 08:31
  • For which type does it fail? For `WriteReply` which only has 4 template parameters and where `get<4>` cannot work? Why do you say that `varReply.value` "doesn't work"? What exactly does that mean? – Werner Henze Dec 04 '18 at 09:39
  • @WernerHenze It is too simplified. get<4> works only for templates with more than 4 parameters, otherwise it throws an exception. What I mean about varReply.value doesn't work: "t is not a constexpr" in compile error. And I guess it won't work, because t will be a enum type not a Reply type. – Greadimar Dec 04 '18 at 09:47
  • @MrBaPHuk Please put all relevant stuff in the question, not into comments. – Werner Henze Dec 04 '18 at 10:02
  • @WernerHenze done. – Greadimar Dec 04 '18 at 10:07

1 Answers1

1

QVariant only hold useful type information for the built-in types used in Qt. If you have other types, you need to record them elsewhere

class Task: public QObject{ 
public:
    template <class TReply> bool applyReply(TReply reply){
        varReply = QVariant::fromValue(reply);
    }
    template <class TReply> TReply getData(){reply.   
       return varReply.value<TReply>();
    }
    QVariant varReply;
}

void usesWriteTask() {
    Task task;
    task.applyReply(WriteReply());
    // ...
    WriteReply back = tast.getData<WriteReply>();
}

Alternatively, if you have access to boost, you can use boost::variant, which inspired std::variant

class Task: public QObject{ 
public:
     using VarReply = boost::variant<ReadRegReply, WriteReply, ReadRndReply, ReadBlockReply>;
     bool applyReply(VarReply reply) {
         varReply = reply;
     }
     template <class Result> Result getData(boost::static_visitor<Result> & visitor) {
        return varReply.apply_visitor(visitor);
     }
     VarReply varReply;
}
Caleth
  • 52,200
  • 2
  • 44
  • 75
  • The result class will be implemented in different projects, and they shouldn't know about replies type, only collecting data through getData of Task. I was looking for somekind of storage of reply class name and use it in variant.value<"here">. Unfortunately, boost and std::variant are not an option at this time, maybe reconsidered in future – Greadimar Dec 04 '18 at 10:03
  • I marked this as an answer, because I didn't found anything else usefull. I made the kind of usesWriteTask() methods. Thank you – Greadimar Dec 06 '18 at 14:46