C ++:提取boost :: variant元素的大小

时间:2014-11-19 08:51:56

标签: c++ boost

我有一个向量,其中包含带有boost :: variant元素的结构。

现在我必须序列化这个载体。由于规范,我必须计算保存此向量所需的八位字节。现在,我正在寻找一种方法来轻松实现这一目标。

int allSize = 0;

for(auto it=vec.begin(); it != vec.end(); it++){
    //something like size = sizeof(it->variant)
    allsize += size;
}

我试图用

来获取元素的大小
sizeof(it->variant.type())

但这仅显示变量元素的大小(这是te变体中保存的最大元素的大小)

那么,是否有一种简单的方法来获得序列化数据的大小? 或者我是否必须使用大约7个模板来编写访问者?

2 个答案:

答案 0 :(得分:2)

您可以在访问者中执行此操作,如下所示:

/*
template <typename T>
using EnableIf = typename std::enable_if< std::is_pod<T>::value >::type* ;
*/

struct visit: public boost::static_visitor<>
{
    visit(  ): size(0) { }
    template<typename T /*, EnableIf<T> = nullptr */  >
    void operator()(  T& x) const
    {
        size += sizeof ( x ) ;
        //std::cout <<  sizeof ( x ) << ":" << x << '\n';
    }

    std::size_t get_size() const
    { return size ; }
    private:
        mutable std::size_t size ;

};

然后,

visit visito ;
std::for_each( vec.begin(), vec.end(), 
               boost::apply_visitor( visito) );

std::cout << visito.get_size() ;

编辑:删除评论以仅检查sehe评论的POD数据类型,因为保存非pod 所需的字节数可能并不总是等于sizeof(T)

答案 1 :(得分:1)

除了其他答案,你可以

  • 让访问者直接返回size_t
  • 使用稍微更通用的访问者对输出迭代器进行实际序列化:

    struct serializer : public boost::static_visitor<> {
        template<typename T, typename Out>
            void operator()(T const& x, Out& out) const {
            static_assert(boost::is_pod<T>(), "");
            char const* rawp = reinterpret_cast<char const*>(&x);
            std::copy(rawp, rawp+sizeof(T), out);
        }
    };
    

    现在,您可以创建一个serialize函数,该函数可以采用任何变体(实际上是可访问类型):

    template <typename Variant, typename Out>
    Out serialize(Variant const& v, Out into) 
    {
        boost::apply_visitor(boost::bind(serializer(), _1, boost::ref(into)), v);
        return into;
    }
    

    如果您不想序列化(但?)但只是想知道大小,可以传递函数输出迭代器而不是传统的输出迭代器:

    template <typename Variant>
    size_t serialized_size(Variant const& v) {
        size_t octets = 0;
        serialize(v, boost::make_function_output_iterator([&octets](char) { ++octets; }));
        return octets;
    }
    

Live On Coliru

#include <boost/array.hpp> // just as a sample

int main() {
    typedef boost::variant<int, double, boost::array<char, 42> > V;

    std::cout << "With int:      " << serialized_size(V(0)) << "\n";
    std::cout << "With double:   " << serialized_size(V(3.14)) << "\n";
    std::cout << "With array:    " << serialized_size(V(boost::array<char,42>())) << "\n";
}

打印

With int:      4
With double:   8
With array:    42

高级应用程序

为何如此通用?以上可以适用于非POD类型并支持您的用例(“我需要序列化它”);

请在此处查看序列化包含非POD和用户定义类型的变体的矢量: Live On Coliru

注意:

  • 要获得有用的应用程序,您需要以类似的方式实现反序列化
  • 使其对变体很有用, 希望(de)序列化类型鉴别器!

这些留给读者练习。