#include <string>
#include <memory>
#include <vector>

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_;
    }
};

using Packet = std::vector<PacketData>;

int main() {
	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>();
	return 0;
}