c++ std::variant运行时的序列化和反序列化

xzlaal3s  于 2023-03-14  发布在  其他
关注(0)|答案(1)|浏览(253)

你好,我想创建一个序列化类来序列化我的变量设置到文件或缓冲区。我一直做得很好,直到我开始在我的类中实现std::variant<T...>。据我所知。我不能在运行时获得变量类型。它需要在编译时完成。但我想存储在文件中。所以这里是我的代码。

class Serialization
{
private:
    std::vector<char> buffer;
public:
    inline std::size_t size()const{return buffer.size();};
    Serialization()=default;
    template<typename T>
    Serialization& operator<<(const T& val){
        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");
        const auto size = buffer.size();
        buffer.resize(buffer.size()+sizeof(T));
        std::memcpy(buffer.data() + size, static_cast<const void*>(&val), sizeof(T));
        return *this;
    }
    template<typename T>
    Serialization& operator>>(T& val){       
        static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable");            
        std::memcpy(&val, buffer.data(), sizeof(T));
        buffer.erase(buffer.begin(), buffer.begin() + sizeof(T));
        return *this;
    }        
    template<typename T>
    Serialization& operator<<(const std::vector<T>& val) {
        const auto size = val.size();
        *this << size;
        for(const auto& elem : val){
            *this << elem;
        }
        return *this;
    }
    template<typename T>
    Serialization& operator>>(std::vector<T>& val) {
        size_t size;
        *this >> size;
        val.resize(size);
        for(auto& elem : val){
            *this >> elem;
        }
        return *this;
    }
    template< class... Types >
    Serialization& operator<<(const std::variant<Types...>& val) {
        const std::size_t index = val.index();
        *this << index;
        std::visit([&](const auto& value){
            *this << value;
        }, val);
        return *this;
    }
    template< class... Types >
    Serialization& operator>>(std::variant<Types...>& val) {
        std::size_t index;
        *this >> index;
        if (index >= sizeof...(Types)) {
            throw std::out_of_range("Variant index out of range");
        }
        using value_type = std::variant_alternative_t<index, std::variant<Types...>>;
        //auto value = expand_type<Types...>(index);
        value_type value;
        *this >> value;
        val.emplace<index>(std::move(value));
        return *this;
    }
    //I also try this one
    template <typename... Ts>
    [[nodiscard]] std::variant<Ts...>
    expand_type(std::size_t i)
    {
        assert(i < sizeof...(Ts));
        static constexpr std::variant<Ts...> table[] = { Ts{ }... };
        return table[i];
    }
    friend std::ostream & operator << (std::ostream &out, const Serialization &s);
    friend std::istream & operator >> (std::istream &in,  Serialization &s);
    ~Serialization()=default;
};
template<>
Serialization& Serialization::operator<<(const std::string& val){
    const auto size = val.size();
    *this << size;
    buffer.insert(buffer.end(), val.begin(), val.end());
    return *this;
}
template<>
Serialization& Serialization::operator>>(std::string& val) {
    size_t size;
    *this >> size;
    val.resize(size);        
    std::memcpy(&val[0], buffer.data(), size);
    buffer.erase(buffer.begin(), buffer.begin() +size);
    return *this;
}
std::ostream & operator << (std::ostream &out, const Serialization &s){   
    out.write(s.buffer.data(),s.buffer.size());
    return out;
}    
std::istream & operator >> (std::istream &in,  Serialization &s){
    in.seekg(0, std::ios::end);
    s.buffer.resize(in.tellg());
    in.seekg(0, std::ios::beg);
    in.read(s.buffer.data(), s.buffer.size());
    return in;
}

我查看论坛、博客和文档,也问过ChatGPT,但找不到实现的方法。

azpvetkf

azpvetkf1#

使用函数指针数组,您可以执行以下操作:

template< class... Types >
Serialization& operator>>(std::variant<Types...>& val) {
    std::size_t index;
    *this >> index;
    if (index >= sizeof...(Types)) {
        throw std::out_of_range("Variant index out of range");
    }
    using func_t = std::variant<Types...> (Serialization&);
    func_t *funcs[] = {
    [](Serialization& that) -> std::variant<Types...> {
        Types value;
        that >> value;
        return value;
    }...
    };
    val = funcs[index](*this);
    return *this;
}

不幸的是,gcc似乎不支持这一点,您必须使用常规函数/方法而不是lambda

template <typename T, typename Var>
Var impl()
{
    T value;
    *this >> value;
    return value;
}

template< class... Types >
Serialization& operator>>(std::variant<Types...>& val) {
    std::size_t index;
    *this >> index;
    if (index >= sizeof...(Types)) {
        throw std::out_of_range("Variant index out of range");
    }
    using mem_func_t = std::variant<Types...> (Serialization::*)();
    mem_func_t funcs[] = { &Serialization::impl<Types, std::variant<Types...>>... };
    val = this->*(funcs[index])();
    return *this;
}

相关问题