Вопрос

I'm attempting to create a class that will combine variables of multiple types into a single variable which can be used to send to a remote machine and reconstruct the class from this data.

You would construct a new packet, this packet would have the 'data variable', not sure what type of variable this should be, the networking library allows data to be sent as 'const void *'

DataPacket *Packet = new DataPacket();

Add data into the packet, this passes a value of the type you specify and 'appends' it onto the end of the 'data variable'

Packet.AddData<int>(45);
Packet.AddData<bool>(true);
Packet.AddData<const char*>("Test");

Send the packet off, this would actually send the 'data variable' to a remote machine through the networking library

Packet.Send();

Construct a packet on the receiving machine passing it the 'data variable' we sent, this would construct a copy of the packet that was sent from the sending machine

DataPacket *Packet = new DataPacket(Data);

Read out the data in the same order you wrote it moving through the 'data variable' from start to end a little more every time GetData is called

int Var1 = Packet.GetData<int>();
bool Var2 = Packet.GetData<bool>();
const char* Var3 = Packet.GetData<const char*>();

What I'm confused on is what type of variable should this 'data variable' be, How to construct an identical packet from this 'data variable', and how to put variables in and out of the 'data variable' with get set like functions.

Это было полезно?

Решение

EDIT: I seem to have misunderstood your question. If you want to transmit data to a remote machine, i.e. over a network or something you need a serialization library like Boost.Serialization: http://www.boost.org/doc/libs/1_55_0/libs/serialization/doc/index.html. Converting your types, especially non trivial types, to a stream of bytes and then converting them back again is not an easy task. I would go with boost.

My original answer which only works to send data around inside a process but not outside the process:

If you don't want to use boost.any or boost.variant you can roll your own using the excelent non intrusive polymorphism pattern from Sean Parent:

class PacketData{
    struct Context {
        virtual ~Context() = default;
    };
    template<typename T>
    struct Instance : Context {
        Instance(T&& t):data_{std::move(t)}{

        }
        T data_;
    };
    std::unique_ptr<Context> self_;
    public:
    template<typename T>
    PacketData(T in):self_{new Instance<T>{std::move(in)}}{}
    //move is easy, copy is harder ;)

    template<typename T>
    bool isA(){
        return dynamic_cast<Instance<T>*>(self_.get()) != nullptr;
    }
    template<typename T>
    T& asA(){
        if(!isA<T>()){
            throw std::runtime_error("bad cast or something");
        }
        return dynamic_cast<Instance<T>*>(self_.get())->data_;
    }
};

After making this variant class the rest should be easy:

using Packet = std::vector<PacketData>;


Packet packet;
packet.push_back(4);
packet.push_back(4.4f);
packet.push_back(std::string{"test"});
int i = packet[0].asA<int>();
float f = packet[1].asA<float>();
std::string s = packet[2].asA<std::string>();

Here is a live example: http://ideone.com/U7rmOL

If you want speed you could get around the heap allocation by puting a stack allocator in the PacketData class which is big enough to hold the usual data sizes. See http://home.roadrunner.com/~hinnant/stack_alloc.html

Другие советы

There was a technique (I can no longer find, it would seem) illustrated in the GoingNative/channel9. It was something like this:

#include <vector>

class Packet
{
    class Generic
    {};

    template <typename C>
    class Content : public Generic
    {
        C content;
    public:
        Content() : Generic(), content() {}
        Content(const C& c) : Generic(), content(c) {}
        ~Content() {}

        C& getContent() const { return content; }
    };

    std::vector<Generic> packet_content;

public:
    Packet() : packet_content() {}

    template <typename X>
    void add(X x) { packet_content.push_back(Content<X>(x)); }
};


int main()
{
    Packet packet;
    packet.add(5);
    packet.add(std::string("hello"));
    packet.add(55);
    packet.add(false);
    packet.add(std::string("world"));
}
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top